我希望能够将给定键和值作为输入的值分配给对象属性,但仍然能够确定值的类型。解释起来有点困难,因此这段代码应该可以揭示问题:

type JWT = { id: string, token: string, expire: Date };
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) };

function print(key: keyof JWT) {
    switch (key) {
        case 'id':
        case 'token':
            console.log(obj[key].toUpperCase());
            break;
        case 'expire':
            console.log(obj[key].toISOString());
            break;
    }
}

function onChange(key: keyof JWT, value: any) {
    switch (key) {
        case 'id':
        case 'token':
            obj[key] = value + ' (assigned)';
            break;
        case 'expire':
            obj[key] = value;
            break;
    }
}

print('id');
print('expire');
onChange('id', 'def456');
onChange('expire', new Date(2018, 3, 14));
print('id');
print('expire');

onChange('expire', 1337); // should fail here at compile time
print('expire'); // actually fails here at run time

我尝试将value: any更改为value: valueof JWT,但这没有用。

理想情况下,onChange('expire', 1337)将失败,因为1337不是Date类型。

如何将value: any更改为给定键的值?

最佳答案

更新:看起来问题标题吸引了人们寻找所有可能的属性值类型的并集,类似于keyof为您提供所有可能的属性键类型的并集的方式。让我们先帮助那些人。您可以通过将lookup types用作键,将generics用作类似于ValueOfkeyof,如下所示:

type ValueOf<T> = T[keyof T];

这给你
type Foo = { a: string, b: number };
type ValueOfFoo = ValueOf<Foo>; // string | number

对于所述问题,您可以使用比keyof T窄的单个键来仅提取您关心的值类型:
type sameAsString = Foo['a']; // lookup a in Foo
type sameAsNumber = Foo['b']; // lookup b in Foo

为了确保键/值对在函数中正确“匹配”,应使用ojit_a以及查找类型,如下所示:
declare function onChange<K extends keyof JWT>(key: K, value: JWT[K]): void;
onChange('id', 'def456'); // okay
onChange('expire', new Date(2018, 3, 14)); // okay
onChange('expire', 1337); // error. 1337 not assignable to Date

这个想法是keyof T参数允许编译器推断通用的key参数。然后,它要求K与所需的查找类型value相匹配。

希望能有所帮助;祝好运!

08-08 03:34