首页 > 解决方案 > 打字稿:具有键类型的对象受同一对象的其他键限制

问题描述

好的,所以我有这个函数应该从一个对象接收一个键和一个值。不同的键具有与之关联的不同值类型。

我不想有一个通用功能,如:

function updateField(key: string, value: any) {

}

举个例子,我在这里有这个对象:

interface ISessionSpecific {
    students?: number[];
    subject?: number;
    address?: string;
    duration?: string[];
    date?: Date;
}

我想创建一个更新此对象中的字段的函数,但我希望它正确键入...

所以当我打电话时:

const value = something;
updateField('address', value);

如果value不是string类型,它将引发错误;

我试过的:


// First Approach:
type ForField<T extends keyof ISessionSpecific> = {
    field: T;
    value: Required<ISessionSpecific>[T];
};

type Approach1 =
    | ForField<'address'>
    | ForField<'students'>
    | ForField<'date'>
    | ForField<'duration'>
    | ForField<'subject'>;

// Second Approach
type Approach2<T extends ISessionSpecific = ISessionSpecific> = {
    field: keyof T;
    value: T[keyof T];
};

// Testing
const x: [Approach1, Approach2] = [
    { field: 'address', value: 0 }, // Error
    { field: 'address', value: 0 }, // No Error
];

我的第一种方法解决了我的问题,但我认为它太冗长了。因为我创建的这个界面只是一个例子……实际的界面可能要大得多。所以我想知道是否有任何更优雅的方法来做到这一点

标签: typescript

解决方案


您可以利用分布式条件类型来获取类似于Approach1自动生成的类型:

type MapToFieldValue<T, K = keyof T> = K extends keyof T ? { field: K, value: T[K] } : never;

const foo: MapToFieldValue<ISessionSpecific> = { field: 'address', value: 0 } // Expect error;

的结果MapToFieldValue<ISessionSpecific>将是联合等价于:

type ManualMap = {
    field: "students";
    value: number[] | undefined;
} | {
    field: "subject";
    value: number | undefined;
} | {
    field: "address";
    value: string | undefined;
} | {
    field: "duration";
    value: string[] | undefined;
} | {
    field: 'date';
    value: Date | undefined;
}

另一种使用映射类型的方法产生相同的结果(感谢@Titian):

type MapToFieldValue<T> = { [K in keyof T]: { field: K, value: T[K] } }[keyof T]

推荐阅读