[英]How to create a typescript type of all class property values?
I want to create a type
from the property values of an class.我想从 class 的属性值创建一个type
。
class Names {
parents = {
mother: "Susan",
dad: "Mike"
}
children ={
son: "Peter"
}
}
// Result should be a type which is like this: "Susan" | "Mike" | "Peter"
type NamesICanUse = ...
How can I achieve this?我怎样才能做到这一点?
You can use the index signature, this will tell to Typescript to use as many properties you need with different names and their values will be Susan, Mike or Peter您可以使用索引签名,这将告诉 Typescript 使用不同名称的尽可能多的属性,它们的值将是 Susan、Mike 或 Peter
type NamesICanUse = {
[nameKey: string]: 'Susan' | "Mike" | "Peter"
}
export class Names{
parents: NamesICanUse = {
mother: "Susan",
dad: "Mike"
}
children: NamesICanUse ={
son: "Peter"
}
}
In your original definition of Names
, the compiler inferred the type of parents
as {mother: string, dad: string}
and the type of children
as {son: string}
.在您对Names
的原始定义中,编译器将parents
的类型推断为{mother: string, dad: string}
,将children
的类型推断为{son: string}
。 It's forgotten about "Susan"
, "Mike",
and "Peter"
entirely.完全忘记了"Susan"
、 "Mike",
和"Peter"
。 The language assumes that you might want to support changing the properties to other strings, and so it doesn't keep track of the specific string values you initialized the object with.该语言假定您可能希望支持将属性更改为其他字符串,因此它不会跟踪您初始化 object 所使用的特定字符串值。 That means any type manipulation you do would produce string
for NamesICanUse
, which isn't what you're looking for.这意味着您所做的任何类型操作都会为NamesICanUse
生成string
,这不是您要寻找的。
So first you need to tell the compiler that you want those properties to have string literal types corresponding to the specific values you assigned.因此,首先您需要告诉编译器您希望这些属性具有与您分配的特定值相对应的字符串文字类型。 One way to do this is to put const
assertions on your object literals.一种方法是在 object 文字上放置const
断言。 This expresses the intent that the values won't change at all, and so you'd like the type to be as narrow as possible:这表达了值根本不会改变的意图,因此您希望类型尽可能窄:
export class Names {
parents = {
mother: "Susan",
dad: "Mike"
} as const // <--
children = {
son: "Peter"
} as const // <--
}
Now if you inspect the parents
property you'll see its type is {readonly mother: "Susan"; readonly dad: "Mike"}
现在,如果您检查parents
属性,您会看到它的类型是{readonly mother: "Susan"; readonly dad: "Mike"}
{readonly mother: "Susan"; readonly dad: "Mike"}
, and the children
property has type {readonly son: "Peter";}
. {readonly mother: "Susan"; readonly dad: "Mike"}
,而children
属性的类型为{readonly son: "Peter";}
。 And so we can proceed.所以我们可以继续。
If you have an object type T
and you want to get a union of all its known property types, you can index into it with keyof T
, where the keyof
type operator gives a union of known keys.如果您有一个 object 类型T
并且您想要获得其所有已知属性类型的联合,您可以使用keyof T
对其进行索引,其中keyof
类型运算符给出已知键的联合。 That's T[keyof T]
.那是T[keyof T]
。 For example:例如:
interface Foo {
x: 0,
y: "a",
z: true
}
type FooVals = Foo[keyof Foo];
// type FooVals = true | 0 | "a"
You could call this the ValueOf
operation, as mentioned in Is there a `valueof` similar to `keyof` in TypeScript?您可以将此称为ValueOf
操作,如 TypeScript 中是否存在类似于 `keyof` 的`valueof` 中所述? : :
type ValueOf<T> = T[keyof T];
type FooVals2 = ValueOf<Foo>;
// type FooVals2 = true | 0 | "a"
In your case, though, you want to go one level deeper... for each key K
in keyof Names
, you want ValueOf
the property at that key.但是,在您的情况下,您希望 go 更深一层...对于keyof Names
中的每个键K
,您希望ValueOf
该键的属性。 So that would be a nested ValueOf
:所以这将是一个嵌套的ValueOf
:
type NamesICanUse = ValueOf<{ [K in keyof Names]: ValueOf<Names[K]> }>
We can unroll that manually to我们可以手动展开
type NamesICanUse = { [K in keyof Names]: Names[K][keyof Names[K]] }[keyof Names]
// type NamesICanUse = "Susan" | "Mike" | "Peter"
As desired.如预期的。
There are ways to abstract this depending on use case.有一些方法可以根据用例来抽象它。 If you want a DeepValueOf<T>
that gives you the union of all non-object properties/subproperties/subsubproperties/etc of a type, you could write the following recursive conditional type :如果你想要一个DeepValueOf<T>
给你一个类型的所有非对象属性/子属性/子子属性/等的联合,你可以编写以下递归条件类型:
type DeepValueOf<T> =
T extends object ? { [K in keyof T]: DeepValueOf<T[K]> }[keyof T] : T;
And this also works on Names
:这也适用于Names
:
type NamesICanUse = DeepValueOf<Names>;
// type NamesICanUse = "Susan" | "Mike" | "Peter"
You could also hardcode the depth, or a max depth, etc., but I'll stop here.您还可以对深度或最大深度等进行硬编码,但我将在此停止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.