TypeScript中是否有类似于`keyof`的`valueof`?


118

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

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: anyvalue: valueof JWT但是没有用。

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

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

Answers:


219

更新:看起来问题标题吸引了人们寻找所有可能的属性值类型的并集,类似于keyof为您提供所有可能的属性键类型的并集的方式。让我们先帮助那些人。你可以做一个ValueOf类似的keyof,通过查找类型keyof T为关键,就像这样:

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

为了确保键/值对在函数中正确“匹配”,您应该使用泛型以及查找类型,如下所示:

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

想法是,该key参数允许编译器推断通用K参数。然后,它需要valuematchs JWT[K],您需要的查找类型。

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


我想tuple从值创建一个。有机会这样做吗?
Morteza Tourani

这听起来像是一个无关紧要的问题,所以您可能应该在其他地方提出这个问题,并提供一个最小的可复制示例,以便人们一定能理解您的用例。祝好运。
jcalz

1
使用带有函数成员的字符串值枚举遇到问题。要解决此问题,您可以使用type StringValueOf<T> = T[keyof T] & string;。我在字符串枚举上找到的最好的文档是TypeScript 2.9发行说明
karmakaze

41

如果有人仍然valueof出于任何目的寻求实现,这就是我想出的一个方案:

type valueof<T> = T[keyof T]

用法:

type actions = {
  a: {
    type: 'Reset'
    data: number
  }
  b: {
    type: 'Apply'
    data: string
  }
}
type actionValues = valueof<actions>

按预期工作:)返回所有可能类型的联合


2
很好 它几乎解决了我的其他问题,但是该开关似乎根本没有缩小类型。
styfle

我想tuple从值创建一个。有机会这样做吗?
Morteza Tourani

12

还有另一种提取对象的联合类型的方法:

  const myObj = { a: 1, b: 'some_string' } as const;
  type values = typeof myObj[keyof typeof myObj];

结果: 1 | "some_string"


const件事非常有价值,TypeScript会自己提供值并删除重复项。对字典来说非常好。
诺姆

正是我想要的!
Mavrick RMX',

2

感谢现有的答案,可以完美解决问题。只是想添加一个包含此实用程序类型的库,如果您想导入该通用类型。

https://github.com/piotrwitek/utility-types#valuestypet

import { ValuesType } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = ValuesType<Props>;

2

试试这个:

type ValueOf<T> = T extends any[] ? T[number] : T[keyof T]

它适用于数组或普通对象。

// type TEST1 = boolean | 42 | "heyhey"
type TEST1 = ValueOf<{ foo: 42, sort: 'heyhey', bool: boolean }>
// type TEST2 = 1 | 4 | 9 | "zzz..."
type TEST2 = ValueOf<[1, 4, 9, 'zzz...']>

0

单线:

type ValueTypesOfPropFromMyCoolType = MyCoolType[keyof MyCoolType];

通用方法示例:

declare function doStuff<V extends MyCoolType[keyof MyCoolType]>(propertyName: keyof MyCoolType, value: V) => void;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.