常用类型
原始类型
字符串
string
数字
number
布尔值
boolean
官方不建议使用大写开头
String
、Number
、Boolean
。
数组 Arrays
对于 [1, 2, 3]
,其类型可以写成 number[]
、Array<number>
。
any
any
类型表示任何类型,可以访问其任何属性、当作函数调用、赋予任意类型的值等:
let obj: any = { x: 0 };
// 以下代码均不会报错
obj.foo();
obj();
obj.bar = 100;
obj = 'hello';
const n: number = obj;
使用
any
会逃避类型检查,对于一些情况是便利的,但非必要的时候不要使用any
。
noImplicitAny
给编译器 noImplicitAny
标签会将所有 any
视为报错。
类型标注
可以在声明变量的时候标注类型:
let myName: string = 'Talaxy';
但是 TS 会自己尝试推断类型,有些情况下是可以不标注类型的:
// TS 会自己推断出右值是 `string` 类型
let myName = 'Talaxy';
编译器推断不出类型的时候会判为
any
类型。
函数 Functions
可以明确函数参数和返回值的类型,后续的调用会受到检查:
function add(a: number, b: number): number {
return a + b;
}
add(10, 20); // 30
add('12', 20); // ERROR
匿名函数
TS 会在一些情况下会根据上下文检查函数类型是否正确:
const names = ['Alice', 'Bob', 'Eve'];
// TS 会推断出 `s` 是 `string` 类型
// 传入的回调类型应当为 `(string, number, string[]) => void` ,否则编译器会报错
names.forEach((s) => {
console.log(s.toLowerCase());
});
对象 Objects
对象类型的书写不是很难:
// 属性之间可以用 `,` 或 `;` 隔开
function printCoordinate(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoordinate({ x: 3, y: 7 });
可选属性
在属性名后面加上 ?
表示属性可选。同时,在访问可选属性的时候请进行空值检查,否则编译器会报错:
// last 属性是可选的
function printName(obj: { first: string; last?: string }) {
// 编译器会判断你有没有进行控制检查,如果没有会报错
if (obj.last !== undefined) {
console.log(obj.last.toUpperCase());
}
// 或者使用最新的 JavaScript 语法(若为空则输出 `undefined` )
console.log(obj.last?.toUpperCase());
}
// 以下代码均不会报错
printName({ first: 'Bob' });
printName({ first: 'Alice', last: 'Alisson' });
联合类型 Union Types
定义一个联合类型
function printId(id: number | string) {
console.log('Your ID is: ' + id);
}
printId(101); // => "Your ID is: 101"
printId('202'); // => "Your ID is: 202"
printId({ myID: 22342 }); // ERROR: 不能将 `{ myID: number}` 类型赋值给 `string | number` 。
使用联合类型变量
在上述例子中,你可以直接调用 number
和 string
的共同属性方法。如果你想针对其中一个类型( TS 中称为 Narrowing ),你需要对变量类型进行检查,不管是用 if
语句还是 switch
语句判断:
function printId(id: number | string) {
if (typeof id === 'string') {
console.log(id.toUpperCase());
} else {
console.log(id);
}
}
对于数组你也可以直接使用 Array.isArray(x)
。
有一个很经典的例子:
// 返回类型将为 `number[] | string`
function getFirstThree(x: number[] | string) {
// 这里的 `slice` 方法为 `number[]` 和 `string` 共有,所以不需要 Narrowing
return x.slice(0, 3);
}
类型别名
类型别名的语法为:
type Point = {
x: number;
y: number;
};
function printCoordinate(pt: Point) {
// ...
}
printCoordinate({ x: 100, y: 100 });
联合类型一样适用:
type ID = number | string;
类型别名并非新类型,类型别名变量在使用中会以真实类型面貌呈现。
接口 Interfaces
接口定义了一个类型必要的属性:
interface Point {
x: number;
y: number;
}
function printCoordinate(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
let coor = { x: 100, y: 200, z: 300 };
printCoordinate(coor);
上面的例子中,由于
coor
符合Point
属性要求,所以传参成功。
字面量赋值的时候,应当完全满足接口类型:
// ERROR: 不能将类型 `{ x: number; y: number; z: number; }` 分配给类型“Point”。
let coor: Point = { x: 100, y: 200, z: 300 }; // ERROR
类型断言
在上述的例子中,我们可以明确类型来处理报错:
printCoordinate({ x: 100, y: 200, z: 300 } as Point);
let coor: Point = { x: 100, y: 200, z: 300 } as Point;
还有一些情况,比如你在使用 document.getElementById
的时候,TS 只会知道返回了个 HTMLElement
类型的东西,但是你能肯定它返回的类型为 HTMLCanvasElement
。这种情况下可以使用类型断言:
const myCanvas = document.getElementById('main_canvas') as HTMLCanvasElement;
或者用中括号语法(但不能在 .tsx
文件中使用):
const myCanvas = <HTMLCanvasElement>document.getElementById('main_canvas');
类型断言代码会在编译后去除,不会影响运行时行为。
两个无包含关系的类型是不能用类型断言的:
const x = 'hello' as number; // ERROR
有的时候你可能比 TS 更了解代码,你可以通过两段断言进行强制转换:
// 第一次先转为 `any`(或 `unknown` ),第二次再转为目标类型
// 圆括号可以去除
const a = expr as any as T;
字面量类型
字面量本身也可以作为一种类型,可以在声明中应用:
let x: 'hello' = 'hello';
x = 'hello'; // OK
x = 'howdy'; // ERROR
这其实等价于:
// x 的类型为 "hello"
const x = 'hello';
配合上联合类型,可以指定值集合:
function printText(s: string, alignment: 'left' | 'right' | 'center') {
// ...
}
printText('Hello, world', 'left');
printText("G'day, mate", 'centre'); // ERROR
需要记住的是,string
变量并非能用在字面量类型上的:
const req = { url: 'https://example.com', method: 'GET' };
// TS 并不知道 req.method 是什么,所以只能报错
handleRequest(req.url, req.method); // ERROR
非空断言
可以用 !
来否定一个类型为空:
function liveDangerously(x?: number | null) {
console.log(x!.toFixed()); // OK
}
枚举 Enums
见 枚举 Enums
参考
cannot redeclare block scoped variable (typescript) - Stack Overflow