从对象类型创建键/值类型



假设我们有一个类型

type Foo = {
a: string;
b: number;
c: boolean;
}

我现在想为具有给定类型Tkeyvalue的对象定义一个类型,以便直接从键推断值的类型,因此我可以这样做:

const kv1: KeyValue<Foo> = {key: 'a', value: 'STRING'};
const kv2: KeyValue<Foo> = {key: 'b', value: 42};
const kv3: KeyValue<Foo> = {key: 'c', value: true};

如果我只是这样做:

type KeyValue<T> = {
key: keyof T;
value: T[keyof T]
}

…那么显然,这些值将是Foo中所有属性值的并集:

如果我这样做:

type KeyValue<T, K extends keyof T> = {
key: K;
value: T[K]
}

…那么当然,如果显式地键入KeyValue<Foo, 'a'>,我可以创建与Foo:s属性类型匹配的对象字面量,但如果我不专门为每个字面量提供类型和键,而只是简单地执行KeyValue<Foo, keyof Foo>,则每个值将被允许为Foo中任何值的类型,即所有值将是string | number | boolean,而不是从输入的key推断。

最后我希望能够做这样的事情:

const kvs: Array<KeyValue<Foo>> = [
{key: 'a', value: 'STRING'}, // should not compile if value is a number or boolean
{key: 'b', value: 42}, // should not compile if value is a string or boolean
{key: 'c', value: true}, // should not compile if value is a string or number
];
是否有可能从这些约束中派生出KeyValue类型,从而在上面的第二个例子中有效地变成KeyValue<Foo, 'a'> | KeyValue<Foo, 'b'> | KeyValue<Foo, 'c'>,而不必手动编写这个联合?基本上,我想我想要的是能够从当前文字对象中的key的值推断出value的类型。

您不能使用单个KeyValue对象来表示每个键值对,因为这将需要部分推断(对于键)或以某种方式从同一对象中的value属性引用key属性。

但是,您可以使用输入对象创建一个有区别的联合。

type Foo = {
a: string;
b: number;
c: boolean;
}
type KeyValue<T> = {
[P in keyof T]: {
key: P;
value: T[P];
}
}[keyof T];
// with KeyValue<Foo>, this generates the following type
// 
// {
//     key: "a";
//     value: string;
// } | {
//     key: "b";
//     value: number;
// } | {
//     key: "c";
//     value: boolean;
// }
const kvs: Array<KeyValue<Foo>> = [
{key: 'a', value: 40}, // ERROR
{key: 'b', value: true}, // ERROR
{key: 'c', value: "foo"}, // ERROR
];

最新更新