void
-
当一个函数没有返回值时,通常会见到其返回值类型是 void:
// 无论 strictNullChecks 为 true/false,undefined 都可以赋值给 void // 只有 strictNullChecks 为 false,null 可以赋值 void function fn(): void { return undefined; }
-
void 和 never 的区别:
- void 可又被赋值为 null、undefined,never 不能包含任何类型;
- 返回类型为 void 的函数能还执行,但是返回 never 的函数无法正常执行 (死循环/异常终止);
Object 类型
-
Object 类型是指除了原始类型以外的其它类型
// object 类型是指除了原始类型以外的其它类型 const foo: object = function () {}; const foo1: object = []; const foo2: object = {};
-
如果需要明确限制对象类型,则应该使用这种 类型对象字面量 的语法,或者是 「接口」;
// 如果需要明确限制对象类型,则应该使用这种类型对象字面量的语法,或者是「接口」 const obj: { foo: number; bar: string } = { foo: 123, bar: "string" };
数组类型
-
两种方式定义数组:
// 第一种:使用数组泛型,Array<元素类型>: const arr1: Array<number> = [1, 2, 3]; // 第二种:在元素类型后面接上[]: const arr2: number[] = [1, 2, 3];
-
案例:
// 如果是 JS,需要判断是不是每个成员都是数字 // 使用 TS,类型有保障,不用添加类型判断 function sum(...args: number[]) { return args.reduce((prev, current) => prev + current, 0); } sum(1, 2, 3); // => 6
元组类型
-
元组类型允许表示一个 已知 元素数量 和 类型 的数组,各元素的类型不必相同;
-
示例代码:
// 元组类型:在定义数组的时候,类型和数据的个数一开始就已经限定了 let t1: [string, number]; t1 = ['hello', 10]; // OK t1 = [10, 'hello']; // Error t1.push(30); // OK,可以 push 新增 console.log(t1[2]); // Error,不可以访问
任意类型
-
在编程阶段还 不清楚类型的变量 指定一个类型,这种情况下,使用 any 类型直接让它们通过编译阶段的检查;
let foo: any = "string"; foo = 100; foo = true;
-
当一个数组中要存储多个数据,个数不确定,类型不确定,此时也可以使用 any 类型来定义数组,这种情况下也没有错误的提示信息,any 类型有优点,也有缺点;
let list: any[] = [1, true, 'free'] list[1] = 100
函数类型
函数声明
// 可选参数:声明的时候,内部的参数使用了 ? 进行修饰,可选参数必须在最后
// 默认参数:声明的时候,内部的参数有自己的默认值
// 剩余参数:是放在函数声明的时候所有的参数的最后
function sum(a: number, b: number = 10, ...rest: number[]): string {
return "func1";
}
sum(100, 200);
sum(100);
sum(100, 200, 300);
函数表达式
type GetName = (firstName: string, lastName: string) => string;
let getName: GetName = function (firstName, lastName) {
return firstName + lastName;
}
函数的重载
函数签名 = 函数名称 + 函数参数 + 函数参数类型 + 返回值类型四者合成
/**
* 得到a*b的结果
* @param a
* @param b
*/
function combine(a: number, b: number): number;
/**
* 得到a和b拼接的结果
* @param a
* @param b
*/
function combine(a: string, b: string): string;
function combine(a: number | string, b: number | string): number | string {
if (typeof a === "number" && typeof b === "number") {
return a * b;
} else if (typeof a === "string" && typeof b === "string") {
return a + b;
}
throw new Error("a 和 b 必须是相同的类型");
}
const result = combine("a", "b");
类型断言、非空断言、双重断言
-
通过类型断言这种方式可以告诉编译器 “相信我,我知道自己在干什么”;类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构,它没有运行时的影响,只是在编译阶段起作用;
-
示例代码:
TypeScriptTypeScriptTypeScript// 假定这个 nums 来自一个明确的接口 const nums = [110, 120, 119, 112]; // 由于 ts 不确定 res 的类型 const res = nums.find((i) => i > 0); // res: number | undefined // 类型断言方式一: const num1 = res as number; // 类型断言方式二: const num2 = <number>res; // 缺点:JSX 下不能使用
let element: (HTMLElement | null) = document.getElementById('root'); // 非空断言 ! element!.style.color = 'green';
let res: string | number; // 双重断言 console.log(res! as any as boolean); console.log(res! as unknown as boolean);
any、unknown 类型
-
any:任何类型的值可以赋值给 any,同时 any 类型的值也可以赋值给任何类型
let a: any; a = 1; // 通过,a 是 any 类型 a = 'aasd'; // 通过,a 是 any 类型 let b: number = a; // 通过,a 是 any 类型,可以被赋值给任意类型 console.log('b', b); // 打印结果是 aasd,违背了 b 的 number 类型设置,但是不会报错
-
unknown:任何类型的值都可以赋值给 unknown,但 unknown 只能赋值给 unknown 和 any 类型,所以 unknown 实际上是一个类型安全的 any
let a: unknown; a = 1; // 通过,unknown 类型可以被赋任意值 a = 'aasd'; // 通过,unknown 类型可以被赋任意值 let b: number = a; // 报错,unknown 类型只能赋值给 any 类型和 unknown 类型
-
never 是 unknown 的子类型
type isNever = never extends unknown ? true : false;
-
keyof unknown 等于 never
type keys = keyof unknown;
联合类型
-
联合类型 |:指多个类型的合并类型,联合会合并子类型,最终合并成 any 类型;
let myName: string | number; // 只能访问联合中所有共同成员 console.log(myName!.toString()); // 赋值为数字后,能访问 number 的方法 myName = 3; console.log(myName.toFixed(2)); // 赋值为字符串后,能访问 string 的方法 myName = '张三'; console.log(myName.length);
-
可辨析联合类型:可辨识要求联合类型中的每个元素都含有一个单例类型属性
interface Square { kind: 'square'; size: number; } interface Rectangle { kind: 'rectangle'; width: number; height: number; } // 有人仅仅是添加了 `Circle` 类型,希望 TypeScript 能在任何被需要的地方抛出错误 interface Circle { kind: 'circle'; radius: number; } type Shape = Square | Rectangle | Circle; function area(s: Shape) { if (s.kind === 'square') { return s.size * s.size; } else if (s.kind === 'rectangle') { return s.width * s.height; } else { // Error: 'Circle' 不能被赋值给 'never',添加了 Circle 就不会报错了 const _exhaustiveCheck: never = s; } }
交叉类型
-
交叉类型 &:多种类型的集合,交叉会向子类型收敛,最终收敛成 never 类型;
TypeScriptTypeScriptinterface A { name: string, c: number } interface B { age: number, c: number } type C = A & B; let c: C = { name: '张三', age: 10, c: 10 }; let a: A = c; // c 是 a 的子类型 let b: B = c; // c 是 b 的子类型
type AA = string | number; type BB = string | boolean; type CC = AA & BB; // string,CC 是 AA、BB 的子类型
-
出现某些类型存在相同的成员,但对应的类型又不一致
// 非对象类型交叉运算 type N0 = string & number; // never type N1 = any & 1; // any type N2 = any & never; // never // 对象类型交叉运算 type A = { kind: 'a', foo: string }; type B = { kind: 'b', foo: number }; type C = { kind: 'c', foo: number }; type AB = A & B; // never type BC = B & C; // never // 函数类型交叉运算 type A = (a: string, b: string) => void; type B = (a: number, b: number) => void; type AB = A & B let func: AB = (a: number | string, b: number | string) => { }
-
案例
// 合并两个 Object function mixin<T, U>(one: T, two: U) { const result = {} as (T & U); // 获取对象属性,强制类型 (result as T)[key] for (let key in one) (result as T)[key] = one[key]; for (let key in two) (result as U)[key] = two[key]; return result; } // 测试 const x = mixin({ name: '张三' }, { age: 11 }); console.log(x.name, x.age);
类型别名
对已知的一些类型定义名称
type Gender = "男" | "女"
type User = {
name: string
age: number
gender: Gender
}
案例:创建并打印扑克牌
type Color = "♥" | "♠" | "♦" | "♣";
type NormalCard = {
color: Color
mark: number
}
type Deck = NormalCard[];
function createDeck(): Deck {
const deck: Deck = [];
for (let i = 1; i <= 13; i++) {
deck.push({ mark: i, color: "♠" });
deck.push({ mark: i, color: "♣" });
deck.push({ mark: i, color: "♥" });
deck.push({ mark: i, color: "♦" });
}
return deck;
}
function printDeck(deck: Deck) {
let result = "\n";
deck.forEach((card, i) => {
let str = card.color;
if (card.mark <= 10) {
str += card.mark;
}
else if (card.mark === 11) {
str += "J";
}
else if (card.mark === 12) {
str += "Q";
}
else {
str += "K";
}
result += str + "\t";
if ((i + 1) % 4 === 0) {
result += "\n";
}
})
console.log(result);
}
const deck = createDeck();
printDeck(deck);
TypeScript👉 原始数据类型
上一篇