我在结合使用条件类型和计算对象属性名称时遇到了问题。基本上,我是根据输入字符串在数据库中插入行。然后,我根据输入字符串输入返回对象。返回对象中的一个属性是也基于输入字符串的计算名称。因此,看起来typescript已经有了验证它是否正确所需的所有信息,但它总是给我错误。这是一个非常简单的例子。
//types of the table rows from the database
interface FirstTableRow {
id: number,
someFirstRefId: number
};
interface SecondTableRow {
id: number,
someSecondRefId: number
};
//maps which table we're working with to its reference column name
const whichToExtraColumn = {
first: 'someFirstRefId',
second: 'someSecondRefId'
} as const;
//maps the table to the returned row type
type ConstToObj<T> = (T extends 'first'
? FirstTableRow
: T extends 'second'
? SecondTableRow
: never
);
function createFirstOrSecond<
T extends keyof typeof whichToExtraColumn
>(
which: T
): ConstToObj<T> {
//gets the reference column name for this table
const refColumn = whichToExtraColumn[which];
//do database stuff....
const insertId = 1;
//build the inserted row
const test: ConstToObj<T> = {
id: insertId,
[refColumn]: 123
};
// ^ Type '{ [x: string]: number; id: number; }' is not assignable to type 'ConstToObj<T>'
return test;
};我做了一个变通方法,在refColumn上做了一个if-check,然后根据它生成不同的对象。但是使用计算属性名称会容易得多。任何帮助都将不胜感激。
发布于 2021-04-13 01:42:56
您在这里遇到了多个问题:
(1)计算属性名称被加宽,可以说是this is a bug
type Key = "a" | "b";
let a: Key = Math.random() ? "a" : "b";
const result = { [a]: 1 };
// -> { [x: string]: number }因此,在您的示例中,[refColumn]: 123永远不会像您希望的那样运行。
(2)带有泛型参数的函数体不会使用所有可能的子类型进行迭代验证(我猜编译器可能会永远运行),而是使用类型约束进行验证。因此,如果你有两个泛型类型,而一个是从另一个派生出来的,那么Typescript根本不在乎。通常这不是问题,因为通常一种类型直接是另一种类型的子类型:
function assign<A extends B, B extends 1 | 2 | 3>(a: A) {
const b: B = a;
}您已经创建了一个情况并非如此,并且约束检查总是会失败。
(3)不能赋值给延迟条件类型。Typescript不知道条件类型将采用哪个分支(如果它的计算被推迟),因此只能将any分配给它。
function plusOne<A extends 1 | 2>(a: A) {
const b: (A extends 1 ? 2 : 3) = a + 1;
}因此,有了这三个限制,如果不进行手动类型转换,基本上就不可能编写函数。这是为数不多的as any似乎非常合理的案例之一。
https://stackoverflow.com/questions/67061394
复制相似问题