let i = void 2; // i === undefined
复制代码
Why 为何须要void?javascript
由于早期js里,人们能够重写undefined,而后赋予真正的值给它,而void老是返回真正的undefined。java
void function() {
console.log('what')
}()
复制代码
void function aRecursion(i) {
if(i > 0) {
console.log(i--)
aRecursion(i)
}
}(3)
console.log(typeof aRecursion) // undefined
复制代码
函数aRecursion执行完后当即释放, 全局做用域也没法获取到这个引用。由于void老是能够执行它后面的表达式。typescript
function middleware(nextcb) {
if(conditionApplies()){
return void nextcb();
}
}
复制代码
undefined
,由于返回值是动态地,返回值可能会根据方法内的逻辑返回,可是void却能够100%保证返回undefined
。button.onclick = () => void doSomething();
复制代码
定义安全
undefined
的子类型。用法bash
undefined
function () {
console.log('xx')
}
复制代码
void
能够做为类型声明中的参数。declare function iTakeNoParameters(x: void): void 复制代码
此时只有
undefined
能够做为参数传入函数
iTakeNoParameters(undefined) //
iTakeNoParameters(void 2) //
复制代码
void
的最大特色在Typescript
中void
和undefined
最重要的一个区别: void
做为函数返回值的类型时,能够用不一样的类型替换:ui
function doSomething(callback: () => void) {
// 这个回调会永远返回undefined
let c = callback()
//c也是undefined类型
}
// 该返回返回number类型
function aNumberCallback(): number {
return 2;
}
// 其实这个方法就作到了类型安全。
doSomething(aNumberCallback)
复制代码
这种称为typescirpt-substitutability
(可替换性模式), 若是但愿传递函数是返回undefined
的,必须明确显式指定回调的签名是:() => undefined
this
建立Symbol很是简单,使用Symbol
构造出来的实例具备惟一的值:spa
const ACADEMIC_TITLE = Symbol('title')
const ARTICLE_TITLE = Symbol('title')
if(ACADEMIC_TITLE === ARTICLE_TITLE) {
// 两个Symbol永远不会相同
}
复制代码
Switch语句中使用Symbol
debug
const LEVEL_INFO = Symbol('INFO')
const LEVEL_DEBUG = Symbol('DEBUG')
const LEVEL_WARN = Symbol('WARN')
const LEVEL_ERROR = Symbol('ERROR')
function log(msg, level) {
switch(level) {
case LEVEL_WARN:
console.warn(msg); break
case LEVEL_ERROR:
console.error(msg); break;
case LEVEL_DEBUG:
console.log(msg);
debugger; break;
case LEVEL_INFO:
console.log(msg);
}
}
复制代码
做为对象的key
const print = Symbol('print')
const user = {
name: 'Stefan',
age: 37,
[print]: function() {
console.log(`${this.name} is ${this.age} years old`)
}
}
复制代码
这里只须要注意如下几点,就是做为对象的Key时,这个print
是不可枚举的,同时它也是没法被序列化的。
typescript
支持symbol
,它是类型系统中的基本类型。Symbol
自己是全部symbol
值的类型。 它也有一个sub-type
:称为unique symbol
, 它能够声明一个惟一的类型:
const PROD: unique symbol = Symbol('prodution mode');
const DEV: unique symbol = Symbol('Development mode');
复制代码
能够认为是JS里的一个名义类型值。为了获得它的类型须要用typeof
function showWarning(msg: string, mode: typeof DEV | typeof PROD) {
// ...
}
复制代码
Symbols
是名义类型和结构类型之间的中间类型。 这是运行时最接近名义类型的类型,但本质上仍然不是名义类型。
运行时枚举
ts的枚举是结构类型,不是名义类型。 这表示你不能直接将string
值赋值给enum types
:
enum Colors {
Red = 'Red',
Yellow = 'yellow',
Blue = 'blue',
}
const c1: Colors = Colors.Blue;
// 这样倒是不符合语法的 Type '"blue"'没法赋值给'Colors'类型。
const c2: Colors = 'blue';
// false
console.log((Moods.Blue === Moods.Blue));
复制代码
尽管是一样的值,可是enum
里面,就会变得独一无二; 他们在TS里是没法比较的。
在JS里的实现能够使用Symbol来作到:
// All Color symbols
const COLOR_RED: unique symbol = Symbol('RED')
const COLOR_ORANGE: unique symbol = Symbol('ORANGE')
const COLOR_YELLOW: unique symbol = Symbol('YELLOW')
// create enum
const ColorsEnum = {
COLOR_RED,
COLOR_ORANGE,
COLOR_YELLOW,
} as const;
复制代码
typescript
的switch
语句用法
function getHexValue(color) {
switch(color) {
case Colors.COLOR_RED: return '#ff0000'
//...
}
}
复制代码
编译机时以及运行时的类型安全
unique symbol
时,全部的赋值都不能改变。const
声明,TypeScript
就会只容许传入的定义好的Symbol
类型。// 索引类型
type ValuesWithKeys<T, K extends keyof T> = T[K];
type Values<T> = ValuesWithKeys<T, keyof T>;
复制代码
解释
index types
索引类型:为了从对象中选取属性的子集,编译器可以检查使用了动态属性名即索引类型。
// 如下这种索引类型就是为了提示编译器去检查: 传入的参数names中是否为o类型的一个属性。
function pluck<T, K extends keyof T>(o: T, names: k[]): T[K][] {
return names.map(n => o[n]);
}
// 索引类型能够做为函数的类型;, T[K]表示了必须是T类型中的属性。
复制代码
而后利用索引类型,能够在声明函数时,将color
类型缩窄至只容许Colors
类型,而且是Symbol
的键和值,而不是只有Symbol
自己的值。
const ColorEnum = {
[COLOR_RED]: COLOR_RED,
[COLOR_YELLOW]: COLOR_YELLOW,
[COLOR_ORANGE]: COLOR_ORANGE,
[COLOR_GREEN]: COLOR_GREEN,
[COLOR_BLUE]: COLOR_BLUE,
[COLOR_INDIGO]: COLOR_INDIGO,
[COLOR_VIOLET]: COLOR_VIOLET,
}
function getHexValue(color: Values<typeof Colors>) {
switch(color) {
case COLOR_RED:
// super fine, is in our type
case Colors.COLOR_BLUE:
// also super fine, is in our type
break;
case COLOR_BLACK:
// what? What is this??? TypeScript errors 💥
break;
}
}
复制代码
这样就作到了不只在编译时利用了TypeScript
的unique symbol
来保证类型安全性,同时在运行时也能够经过JavaScript
中Symbol
独一无二的特性实现类型安全。