[英]TypeScript conditional type and computed object property names
我在将条件类型与计算的 object 属性名称结合使用时遇到问题。 基本上我是根据输入字符串将行插入到数据库中。 然后我根据该输入字符串键入返回 object。 返回 object 中的属性之一是计算名称,它也基于输入字符串。 所以看起来 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 来解决此问题,然后根据它生成不同的对象。 但是使用计算属性名称会更容易。 任何帮助,将不胜感激。
您在这里遇到了多个问题:
(1) 计算属性名称被加宽,有人可能会说这是一个错误:
type Key = "a" | "b";
let a: Key = Math.random() ? "a" : "b";
const result = { [a]: 1 };
// -> { [x: string]: number }
因此,您的示例[refColumn]: 123
永远不会按照您的意愿行事。
(2) Function 具有泛型参数的函数体没有使用所有可能的子类型进行迭代验证(我猜编译器可能会永远运行),而是使用类型约束验证它们。 因此,如果您有两种泛型类型,而一种是从另一种派生的,则 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;
}
因此,有了这三个限制,基本上不可能在没有手动类型转换的情况下编写 function。 这是为数不多的案例之一, as any
看起来都非常合理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.