Ste*_*n G 18 generics enums typescript
请考虑以下typescript枚举:
enum MyEnum { A, B, C };
Run Code Online (Sandbox Code Playgroud)
如果我想要另一种类型是该枚举键的联合字符串,我可以执行以下操作:
type MyEnumKeysAsStrings = keyof typeof MyEnum; // "A" | "B" | "C"
Run Code Online (Sandbox Code Playgroud)
这非常有用.
现在我想以这种方式创建一个在枚举上普遍运行的泛型类型,这样我就可以说:
type MyEnumKeysAsStrings = AnyEnumKeysAsStrings<MyEnum>;
Run Code Online (Sandbox Code Playgroud)
我想是正确的语法是:
type AnyEnumKeysAsStrings<TEnum> = keyof typeof TEnum; // TS Error: 'TEnum' only refers to a type, but is being used as a value here.
Run Code Online (Sandbox Code Playgroud)
但是这会产生编译错误:"'TEnum'只引用一个类型,但在这里被用作值."
这是出乎意料和悲伤的.通过从泛型声明的右侧删除typeof,并将其添加到特定类型声明中的type参数,我可以通过以下方式完全解决它:
type AnyEnumAsUntypedKeys<TEnum> = keyof TEnum;
type MyEnumKeysAsStrings = AnyEnumAsUntypedKeys<typeof MyEnum>; // works, but not kind to consumer. Ick.
Run Code Online (Sandbox Code Playgroud)
我不喜欢这种解决方法,因为这意味着消费者必须记住在通用上指定typeof.
是否有任何语法允许我指定我最初想要的泛型类型,以便对消费者友好?
jca*_*alz 42
没有,消费者将需要使用typeof MyEnum引用的键是对象A,B和C.
前面有很长的解释,你可能已经知道了
您可能知道,TypeScript会向JavaScript添加静态类型系统,并且在编译代码时会删除该类型系统.TypeScript的语法是这样的,一些表达式和语句引用运行时存在的值,而其他表达式和语句引用仅在设计/编译时存在的类型.值具有类型,但它们本身不是类型.重要的是,在代码中有一些地方,编译器会期望一个值,并在可能的情况下将它找到的表达式解释为值,以及编译器期望类型的其他位置,并在可能的情况下将它找到的表达式解释为类型.
如果表达式可以被解释为值和类型,则编译器不关心或混淆. 例如,使用null以下代码中的两种风格非常高兴:
let maybeString: string | null = null;
Run Code Online (Sandbox Code Playgroud)
第一个实例null是类型,第二个实例是值.它也没有问题
let Foo = {a: 0};
type Foo = {b: string};
Run Code Online (Sandbox Code Playgroud)
其中第一个Foo是命名值,第二个Foo是命名类型.需要注意的是值的类型Foo为{a: number},而类型Foo为{b: string}.他们不一样.
即使typeof操作员也能过上双重生活. 表达式typeof x总是期望x是一个值,但typeof x它本身可以是一个值或类型,具体取决于上下文:
let bar = {a: 0};
let TypeofBar = typeof bar; // the value "object"
type TypeofBar = typeof bar; // the type {a: number}
Run Code Online (Sandbox Code Playgroud)
该行将let TypeofBar = typeof bar;通过JavaScript,它将在运行时使用JavaScript typeof运算符并生成一个字符串.但是type TypeofBar = typeof bar; 被擦除,它使用TypeScript类型查询运算符来检查TypeScript已分配给名为的值的静态类型bar.
现在,TypeScript中引入名称的大多数语言构造都会创建命名值或命名类型.以下是一些命名值的介绍:
const value1 = 1;
let value2 = 2;
var value3 = 3;
function value4() {}
Run Code Online (Sandbox Code Playgroud)
这里有一些命名类型的介绍:
interface Type1 {}
type Type2 = string;
Run Code Online (Sandbox Code Playgroud)
但也有其创建一些声明既名为值和命名类型,并且,像Foo上面的命名值的类型不是指定的类型.大的有class和enum:
class Class { public prop = 0; }
enum Enum { A, B }
Run Code Online (Sandbox Code Playgroud)
这里,类型 Class是类型实例的Class,而值 Class是构造物体.而typeof Class不是Class:
const instance = new Class(); // value instance has type (Class)
// type (Class) is essentially the same as {prop: number};
const ctor = Class; // value ctor has type (typeof Class)
// type (typeof Class) is essentially the same as new() => Class;
Run Code Online (Sandbox Code Playgroud)
并且,类型 Enum是枚举元素的类型; 每个元素的类型的联合.虽然值 Enum是一个对象,其键是A和B,其属性是枚举的元素.而typeof Enum不是Enum:
const element = Math.random() < 0.5 ? Enum.A : Enum.B;
// value element has type (Enum)
// type (Enum) is essentially the same as Enum.A | Enum.B
// which is a subtype of (0 | 1)
const enumObject = Enum;
// value enumObject has type (typeof Enum)
// type (typeof Enum) is essentially the same as {A: Enum.A; B: Enum.B}
// which is a subtype of {A:0, B:1}
Run Code Online (Sandbox Code Playgroud)
现在支持你的问题.您想要发明一个类似于此的类型运算符:
type KeysOfEnum = EnumKeysAsStrings<Enum>; // "A" | "B"
Run Code Online (Sandbox Code Playgroud)
你把类型 放在哪里Enum,并获取对象 的键Enum.但是如上所述,类型Enum与对象不同Enum.不幸的是,这种类型对价值一无所知.这有点像说:
type KeysOfEnum = EnumKeysAsString<0 | 1>; // "A" | "B"
Run Code Online (Sandbox Code Playgroud)
很明显,如果你这样写,你会发现你无法对0 | 1产生该类型的类型做任何事情"A" | "B".为了使它工作,你需要传递一个知道映射的类型.那种类型是typeof Enum......
type KeysOfEnum = EnumKeysAsStrings<typeof Enum>;
Run Code Online (Sandbox Code Playgroud)
这就像
type KeysOfEnum = EnumKeysAsString<{A:0, B:1}>; // "A" | "B"
Run Code Online (Sandbox Code Playgroud)
这是可能的......如果type EnumKeysAsString<T> = keyof T.
所以你被困在让消费者指定typeof Enum.有变通方法吗?好吧,你可以使用一些能够做到这一点的东西,比如一个函数?
function enumKeysAsString<TEnum>(theEnum: TEnum): keyof TEnum {
// eliminate numeric keys
const keys = Object.keys(theEnum).filter(x =>
(+x)+"" !== x) as (keyof TEnum)[];
// return some random key
return keys[Math.floor(Math.random()*keys.length)];
}
Run Code Online (Sandbox Code Playgroud)
然后你可以打电话
const someKey = enumKeysAsString(Enum);
Run Code Online (Sandbox Code Playgroud)
和类型someKey将是"A" | "B".是的,但然后将其用作类型,你必须查询它:
type KeysOfEnum = typeof someKey;
Run Code Online (Sandbox Code Playgroud)
这会迫使你typeof再次使用,并且比你的解决方案更加冗长,特别是因为你不能这样做:
type KeysOfEnum = typeof enumKeysAsString(Enum); // error
Run Code Online (Sandbox Code Playgroud)
Blegh.抱歉.
要收回:
希望这有点道理.祝好运.
Pas*_*aye 26
有一个解决方案不需要创建新的泛型类型。
如果你声明一个枚举
enum Season { Spring, Summer, Autumn, Winter };
Run Code Online (Sandbox Code Playgroud)
要获取类型,您只需要使用关键字keyof typeof
let seasonKey: keyof typeof Season;
Run Code Online (Sandbox Code Playgroud)
然后变量按预期工作
seasonKey = "Autumn"; // is fine
// seasonKey = "AA" <= won't compile
Run Code Online (Sandbox Code Playgroud)
Akx*_*kxe 13
这实际上是可能的。
enum MyEnum { A, B, C };
type ObjectWithValuesOfEnumAsKeys = { [key in MyEnum]: string };
const a: ObjectWithValuesOfEnumAsKeys = {
"0": "Hello",
"1": "world",
"2": "!",
};
const b: ObjectWithValuesOfEnumAsKeys = {
[MyEnum.A]: "Hello",
[MyEnum.B]: "world",
[MyEnum.C]: "!",
};
// Property '2' is missing in type '{ 0: string; 1: string; }' but required in type 'ObjectWithValuesOfEnumAsKeys'.
const c: ObjectWithValuesOfEnumAsKeys = { // Invalid! - Error here!
[MyEnum.A]: "Hello",
[MyEnum.B]: "world",
};
// Object literal may only specify known properties, and '6' does not exist in type 'ObjectWithValuesOfEnumAsKeys'.
const d: ObjectWithValuesOfEnumAsKeys = {
[MyEnum.A]: "Hello",
[MyEnum.B]: "world",
[MyEnum.C]: "!",
6: "!", // Invalid! - Error here!
};
Run Code Online (Sandbox Code Playgroud)
编辑:解除限制!
enum MyEnum { A, B, C };
type enumValues = keyof typeof MyEnum;
type ObjectWithKeysOfEnumAsKeys = { [key in enumValues]: string };
const a: ObjectWithKeysOfEnumAsKeys = {
A: "Hello",
B: "world",
C: "!",
};
// Property 'C' is missing in type '{ 0: string; 1: string; }' but required in type 'ObjectWithValuesOfEnumAsKeys'.
const c: ObjectWithKeysOfEnumAsKeys = { // Invalid! - Error here!
A: "Hello",
B: "world",
};
// Object literal may only specify known properties, and '6' does not exist in type 'ObjectWithValuesOfEnumAsKeys'.
const d: ObjectWithKeysOfEnumAsKeys = {
A: "Hello",
B: "world",
C: "!",
D: "!", // Invalid! - Error here!
};
Run Code Online (Sandbox Code Playgroud)
const enum太!小智 5
您可以只传递 atype而不是 a value,编译器不会抱怨。typeof正如您所指出的,您可以实现这一目标。
会稍微不那么自动化:
type AnyEnumKeysAsStrings<TEnumType> = keyof TEnumType;
Run Code Online (Sandbox Code Playgroud)
您可以将其用作:
type MyEnumKeysAsStrings = AnyEnumKeysAsStrings<typeof MyEnum>;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6074 次 |
| 最近记录: |