简体   繁体   English

TypeScript 条件类型和计算 object 属性名称

[英]TypeScript conditional type and computed object property names

I'm having trouble using a conditional type in combination with a computed object property name.我在将条件类型与计算的 object 属性名称结合使用时遇到问题。 Basically I'm inserting rows into a database based on an input string.基本上我是根据输入字符串将行插入到数据库中。 Then I'm typing the return object based on that input string.然后我根据该输入字符串键入返回 object。 One of the properties in the return object is a computed name that is also based on the input string.返回 object 中的属性之一是计算名称,它也基于输入字符串。 So it seems like typescript would have all the info needed to verify that this is correct but it keeps giving me errors.所以看起来 typescript 将拥有验证这是否正确所需的所有信息,但它一直给我错误。 Here's a very simplified example.这是一个非常简化的示例。


//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;

};

I made a workaround by doing an if-check on refColumn , then generating different objects depending on that.我通过对refColumn进行 if-check 来解决此问题,然后根据它生成不同的对象。 But using a computed property name would be waayyy easier.但是使用计算属性名称会更容易。 Any help would be appreciated.任何帮助,将不胜感激。

You are running into multiple issues here:您在这里遇到了多个问题:

(1) Computed property names are widened, one might say this is a bug : (1) 计算属性名称被加宽,有人可能会说这是一个错误

type Key = "a" | "b";
let a: Key = Math.random() ? "a" : "b";
const result = { [a]: 1 };
//    -> { [x: string]: number }

So your example, [refColumn]: 123 will never behave as you want it to.因此,您的示例[refColumn]: 123永远不会按照您的意愿行事。

(2) Function bodies of functions with generic parameters are not validated iteratively with all possible subtypes (I guess the compiler might run forever then), instead they are validated with the type constraint. (2) Function 具有泛型参数的函数体没有使用所有可能的子类型进行迭代验证(我猜编译器可能会永远运行),而是使用类型约束验证它们。 Thus if you have two generic types, whereas one is derived from the other, Typescript simply does not care.因此,如果您有两种泛型类型,而一种是从另一种派生的,则 Typescript 根本不在乎。 Usually this is not a problem because usually one type is directly the subtype of the other:通常这不是问题,因为通常一种类型直接是另一种的子类型:

function assign<A extends B, B extends 1 | 2 | 3>(a: A) {
    const b: B = a;
}

You've created a case where this is not the case, and constraint checking will always fail.您已经创建了一个并非如此的案例,并且约束检查将始终失败。

(3) One just cannot assign to a deferred conditional type. (3) 不能分配给延迟条件类型。 Typescript does not know which branch the conditional type will take (if it's evaluation is deferred), and as such only any can be assigned to it. Typescript 不知道条件类型将采用哪个分支(如果它的评估被延迟),因此只能将any分支分配给它。

function plusOne<A extends 1 | 2>(a: A) {
    const b: (A extends 1 ? 2 : 3) = a + 1;
}

So with these three limitations it is basically impossible to write your function without manual typecasts.因此,有了这三个限制,基本上不可能在没有手动类型转换的情况下编写 function。 This is one of the few cases were an as any seems very reasonable.这是为数不多的案例之一, as any看起来都非常合理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM