类型检查
类型兼容性
x、y属性一样,多的那个类型可以被赋值给少的那个
interface x {
a: number;
b: number;
}
interface y {
a: number;
b: number;
c: number;
}
let aobj: x = { a: 1, b: 2 };
let bobj: y = { a: 1, b: 2, c: 3 };
aobj = { a: 1, b: 2, c: 3 };// 不可以
aobj = bobj; // 可以
bobj = aobj;// 不可以
函数兼容性
type Handler = (a:number,b:number) => void;
function task(params: Handler) {
return params;
}
入参为基础数据类型
- 入参多的可以兼容入参少的
- 返回值是对象,属性少的可以兼容属性多的
- 可选参数与剩余参数:
type Handler1 = (a: number, b: number) => void;// 固定参数
type Handler2 = (a?: number, b?: number) => void;// 可选参数
type Handler3 = (...rest: number[]) => void;// 剩余参数
let h1: Handler1 = (a: number, b: number) => { };
let h2: Handler2 = (a?: number, b?: number) => { };
let h3: Handler3 = (...rest: number[]) => { };
h1 = h2 = h3;
- 剩余参数视为无限多参数,由于第1条成立,所以剩余参数可以兼容固定参数和可选参数
修改
"strictFunctionTypes": false,
- 剩余参数可以兼容固定参数和可选参数
- 可选参数可以兼容固定参数和可选参数
入参为对象
- 对象属性多的可以兼容对象属性少的;可以理解为入参多的可以兼容入参少的。
interface Point2D{
x: number;
y: number;
}
interface Point3D{
x: number;
y: number;
z: number;
}
let p2d=(point: Point2D) => { };
let p3d = (point: Point3D) => { };
p2d = p3d;// 不可以 修改"strictFunctionTypes": false, 可以
p3d = p2d;// 可以
返回值类型
- 返回为对象,则属性少的兼容属性多的
枚举兼容性
enum Fruit {
Apple = 2,
Banana = 3
}
let a: number = Fruit.Apple;// 可以
Fruit.Apple = Fruit.Banana;// 不可以
类兼容
class A {
state: number;
constructor(val: number) {
this.state = val;
}
run(): number {
return this.state;
}
}
class B {
state: number;
static id: number;
constructor(val: string) {
}
run(): number {
return this.state;
}
walk(): number {
return;
}
}
let a = new A(1);
let b = new B('b');
a = b;// 可以
b = a;// 不可以
- 静态成员和构造函数不参与比较
- 类的私有成员和受保护成员,只允许子类赋值给父类
泛型兼容
interface A<T>{
data: T;
}
let x: A<number>;
let y: A<string>;
x = y; // T被使用时不可以,不被使用时可以
- 没有指定类型兼容时,T视为any
高级类型
交叉类型
interface A {
run(): void;
}
interface B {
walk(): void;
}
let c: A & B = {
run() { },
walk() { }
}
联合类型
let x: string | number;
let y: 'a' | 'b' | 'c';
let z = 1 | 2 | 3 | 4;
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(s: Shape) {
switch (s.kind) {
case "square":
return s.size * s.size;
case "rectangle":
return s.height * s.width;
default:
return ((e: never) => { throw new Error(e) })(s)
// 约束在type而不给case处理的情况,即强制要求每一个type都必须处理
}
}
索引类型
// keyof T
interface Obj {
a: number,
b: string
}
let key: keyof Obj;
// T[K]
let value: Obj['a']
// T extends U
function getValue<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key]);
}
映射类型
interface Obj {
a: string;
b: string;
c: number;
}
// 同态
// 把所有类型变成只读的
type ReadonlyObj = Readonly<Obj>;
// 把所有类型变成可选的
type PartialObj = Partial<Obj>;
// 限定选取范围
type PickObj = Pick<Obj, 'a' | 'b'>;
// 非同态:会创建新的属性
// x,y属性都是Obj类型
type RecordObj = Record<'x' | 'y', Obj>;
let obj: RecordObj = {
x: {
a: 'a',
b: 'b',
c: 1
},
y: {
a: 'a',
b: 'b',
c: 1
}
}
namespace
- 使用export将function导出
namespace Square{
let a = 1;
let b = 2;
export function task() {
return a + b;
}
}
Square.task();
编译
合并
- 两个文件有同名的命名空间,则命名空间会发生合并,但不能有同名export的东西;
- 与函数合并
命名空间声明需要放在后面。
function Lib() { }
namespace Lib {
export let version = '1.0';
}
console.log(Lib.version);// 1.0
- 与类合并
命名空间声明需要放在后面。
class C { }
namespace C {
export let state = 1;
}
console.log(C.state);// 1
state为class C的静态成员
- 与enum合并
命名空间声明可以不放在后面。
enum Color {
Red,
Yellow,
Bule
}
namespace Color {
export function mix() { }
}
console.log(Color);
网友评论