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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49285864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:53:03  来源:igfitidea点击:

Is there a `valueof` similar to `keyof` in TypeScript?

typescripttypes

提问by styfle

I want to be able to assign an object property to a value given a key and value as inputs yet still be able to determine the type of the value. It's a bit hard to explain so this code should reveal the problem:

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

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

I tried changing value: anyto value: valueof JWTbut that didn't work.

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

Ideally, onChange('expire', 1337)would fail because 1337is not a Date type.

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

How can I change value: anyto be the value of the given key?

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

回答by jcalz

UPDATE: Looks like the question title attracts people looking for a union of all possible property value types, analogous to the way keyofgives you the union of all possible property key types. Let's help those people first. You can make a ValueOfanalogous to keyof, by using lookup typeswith keyof Tas the key, like so:

更新:看起来问题标题吸引人们寻找所有可能的属性值类型的联合,类似于keyof为您提供所有可能的属性键类型的联合的方式。让我们先帮助那些人。您可以通过使用带有作为键的查找类型来创建ValueOf类似于,如下所示:keyofkeyof T

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

which gives you

这给了你

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


For the question as stated, you can use individual keys, narrower than keyof T, to extract just the value type you care about:

对于上述问题,您可以使用比 窄的单个键keyof T来提取您关心的值类型:

type sameAsString = Foo['a']; // lookup a in Foo
type sameAsNumber = Foo['b']; // lookup b in Foo

In order to make sure that the key/value pair "match up" properly in a function, you should use genericsas well as lookup types, like this:

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

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

The idea is that the keyparameter allows the compiler to infer the generic Kparameter. Then it requires that valuematches JWT[K], the lookup type you need.

这个想法是key参数允许编译器推断泛型K参数。然后它需要value匹配JWT[K],您需要的查找类型。

Hope that helps; good luck!

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

回答by Chris Kowalski

If anyone still looks for implementation of valueoffor any purposes, this is a one I came up with:

如果有人仍然valueof出于任何目的寻找实现,这是我想出的:

type valueof<T> = T[keyof T]

Usage:

用法:

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

Works as expected :) Returns an Union of all possible types

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

回答by Dima

There is another way to extract the union type of the object:

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

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

Result: 1 | "some_string"

结果: 1 | "some_string"

回答by Billy Chan

Thanks the existing answers which solve the problem perfectly. Just wanted to add up a lib has included this utility type, if you prefer to import this common one.

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

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

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

回答by Zheeeng

Try this:

尝试这个:

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

It works on an array or a plain object.

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

// 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...']>

回答by José Cabo

One-liner:

单线:

type ValueTypesOfPropFromMyCoolType = MyCoolType[keyof MyCoolType];

Example on a generic method:

泛型方法示例:

declare function doStuff<V extends MyCoolType[keyof MyCoolType]>(propertyName: keyof MyCoolType, value: V) => void;