简体   繁体   English

如何创建所有 class 属性值的 typescript 类型?

[英]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 = ...

TS Playground TS游乐场

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.您还可以对深度或最大深度等进行硬编码,但我将在此停止。

Playground link to code Playground 代码链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何创建 Typescript 装饰器,根据以“_”开头的属性名称将所有 class 属性设置为不可枚举? - How to create Typescript decorator that sets all class properties as non-enumerable based on property name starting with “_”? 如何确保扩展类必须在TypeScript中设置属性值? - How to ensure that an extending class must set property values in TypeScript? 在 typescript 中声明 object 中的所有属性相同类型? - declare all property in object the same type in typescript? 检查对象是否具有打字稿中类的所有属性 - check if an object have all the property of a class in typescript 如何将对象中的所有属性值转换为字符串类型? - How do I convert all property values in an object to type string? 为特定类类型的数组创建打字稿扩展 - Create typescript extension for array of particular class type 如何在 TypeScript 中创建动态 class? - How to create a dynamic class in TypeScript? TypeScript - 如何动态创建 class? - TypeScript - How to dynamically create class? React Class 组件属性中的 TypeScript 错误在类型“Readonly&lt;{}&gt;”上不存在,不确定如何为 state 设置类型 - TypeScript errors in React Class Component property does not exist on type 'Readonly<{}>', not sure how to set types for state TypeScript:如何创建一个包装类,该包装类具有基类的所有方法而无需手动声明? - TypeScript: How do you create a wrapper class that has all the methods of the base class without manually declaring?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM