1.在泛型约束中使用类型参数
你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj
上,因此我们需要在这两个类型之间使用约束。
function getProperty(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
wtf,这那里约束了?文档当中其实少写了泛型约束。应该是:
function getProperty<T,K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
其实这样写也是可以的:
function getProperty<T,k>(obj: T, key: keyof T) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
2.数字枚举
数字枚举可以被混入到 计算过的和常量成员(如下所示)。 简短地说,不带初始化器的枚举或者被放在第一的位置,或者被放在使用了数字常量或其它常量初始化了的枚举后面。 换句话说,下面的情况是不被允许的:
enum E {
A = getSomeValue(),
B, // error! 'A' is not constant-initialized, so 'B' needs an initializer
}
这句话想表达的意思其实是,没有初始化的枚举,只能放在第一的位置或者放在使用了计算过的和数字常量的枚举后面。因为没有初始化的枚举默认累加上一个枚举的值。当然一般指的都是数字枚举,虽然异构枚举也是允许的。
3.反向映射
除了创建一个以属性名做为对象成员的对象之外,数字枚举成员还具有了 反向映射,从枚举值到枚举名字。 例如,在下面的例子中:
enum Enum {
A
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
生成的代码中,枚举类型被编译成一个对象,它包含了正向映射( name
-> value
)和反向映射( value
->name
)。 引用枚举成员总会生成为对属性访问并且永远也不会内联代码。
这段话的意思是,枚举类型编译后生成的其实是一个对象,包含了正向和反向映射,引用枚举成员其实相当于对编译后的这个对象的属性的访问。至于永远不会内联代码的意思指的是,编译后不会把引用枚举成员转换成具体的值。比如不会把Enum[a]转换成0。