基础类型的分类
常用
- boolean: 布尔值
- number: 支持2/8/10/16进制
- string: 字符串
- enum: 枚举类型,可根据value找到key
- array: 普通数组,有2种方式,string[]或者
Array<string>
- tuple: 特殊数组,指定数组里的每个元素的类型,同时也确定了元素个数
其他
- any: 不确定类型的变量
- void: 没有任何返回值的函
- undefined/null: 2种特殊类型
- <>: 非常确定的类型
array和tuple的区别?
// array例子: 数组元素类型相同,都是string
let arr1: string[] = ['a','b'];
// tuple例子: 数组元素类型可以不同
let tp1: [number, string] = [1,'abc'];
boolean
// boolean
let isDone: boolean = true;
let disabled: boolean = false;
console.log(`isDone: ${isDone}`); // isDone: true
console.log(`disabled: ${disabled}`); //disabled: false
number
// number 可以是 十进制,十六进制,八进制,二进制
let n1: number = 666;
let n2: number = 0x0a;
let n3: number = 0o17;
let n4: number = 0b11;
console.log(`n1: ${n1}`); // n1: 666
console.log(`n2: ${n2}`); // n2: 10
console.log(`n3: ${n3}`); // n3: 15
console.log(`n4: ${n4}`); // n4: 3
string
// string 支持模板字符串
let myname: string = 'john';
let myage: number = 18;
let greeting: string = `i am ${myname} and i am ${myage} years old!`
console.log(greeting); // i am john and i am 18 years old!
// 对比 string 和 String
// 1. 普通变量 小写string
export type Todo = {
id: number,
title: string,
completed: boolean
}
// 2. Vue props变量 大写String
defineProps({
msg:{
type: String
}
})
object
// object类型
let obj_1:object;
obj_1 = {name:'peter'};
console.log(`obj_1:`,obj_1); // obj_1: { name: 'peter' }
array
// 2种array定义方式
let arr1: string[] = ['a','b'];
let arr2: Array<number> = [1,2,3]; // 数组泛型
console.log(arr1); // [ 'a', 'b' ]
console.log(arr2); // [ 1, 2, 3 ]
类数组是什么?
- 比如 arguments 是类数组,不能用普通数组类型,应该用interface类型
- 比如 let args:IArguments = arguments
- 其他常见的类数组interface有: IArguments, NodeList, HTMLCollection 等
arguments 的1种错误类型和2种正确类型图解如下
tuple
// tuple 元组
// 特殊的数组 定义了类型和数目的数组(指定每个元素的类型)
let tp1: [number, string] = [1,'abc'];
let tp2: [number, string, string] = [1,'abc', ''];
tp2[2] = 'x'; // ok
tp2[3] = 'y'; // error y is not assignable to type => tuple定义后,不能再新增元素
enum
// 先定义枚举集合
enum Color {Red = 2, Green = 1, Blue};
// 使用1: 获取枚举常量值
let c1: Color = Color.Red; // c1=2
let c2: Color = Color.Green; // c2=1
let c3: Color = Color.Blue; // c3=2 自动计算
// 使用2: 通过常量值反过来获取对应的key
let cname1: string = Color[2]; // cname1='Blue'
any
// 任意值 不确定类型的变量
let notSure: any;
notSure = 1; // OK
notSure = 'abc'; // OK
// 变量声明未指定其类型 会被识别为任意值类型
let a; // 等价于 let a:any;
void
// void: 表示没有任何类型
// 使用场景: 函数没有返回值的情况
function f1(): void{
console.log('no return');
}
function f2(): string{
return 'have return'
}
console.log(f1()); // void -> no return
console.log(f2()); // have return
undefined null
// undefined null
let empty1: undefined = undefined;
let empty2: null = null;
console.log(empty1); // undefined
console.log(empty2); // null
内置对象
- ECMAScript 的内置对象 Boolean、Error、Date、RegExp
- DOM 和 BOM 的内置对象 Document、HTMLElement、Event、NodeList
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent){
// do something
})
自动类型推论 type inference
// 1. 变量定义时有赋值: 根据[赋值]推测出[类型]
let myName = 'Jim'; // 推断类型为string
myName = 7; //error: type number
// 2. 定义时没有赋值: 被推断成 [any 类型]
let myName; // 推断类型为any
myName = 'Jim'; //ok
myName = 7; //ok
联合类型 union types
// 什么是联合类型? 变量可能为多种类型
let myLuckyNumber : string | number;
myLuckyNumber = 'two' // OK
myLuckyNumber = 2 // OK
// 联合类型自动推断
let myLuckyNumber : string | number;
myLuckyNumber = 'two'
console.log(myLuckyNumber.length) // OK 类型推断为string length ok
myLuckyNumber = 2 // OK
console.log(myLuckyNumber.length) // 类型推断为string number no! 报错: Property 'length' does not exist on type 'number'.
// 联合类型变量的方法调用
function getString1(luck: string | number):string{
return luck.toString() // OK 因为 string number 都存在 toString 方法
}
function getString2(luck: string | number):string{
return luck.slice(1)// ERROR 因为 string 有slice方法,但是 number 没有 slice方法
}
类型别名 type aliases
// 语法: 关键字是type
// 用途: 常用于联合类型
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
类型断言 type assertion
类型断言:
- 表示程序员非常确认类型,可以实现类型自动转化
// 语法1. as关键字 ,如 str as string, counter as number
let verysure: any = 'very sure type';
let len: number = (verysure as string).length;
console.log(verysure); // very sure type
console.log(len); // 14
// 语法2. 尖括号,如`<string>str, <number>counter`
let verysure: any = 'very sure type';
let len: number = (<string>verysure).length;
console.log(verysure); // very sure type
console.log(len); // 14
泛型 Generics
// without Generics
function genArray (n: Number, v: any): Array<any> {
let result = [];
for(let i=0; i<n; i++){
result[i] = v;
}
return result; // 返回N个v数组 [v,v,...]
}
// with Generics
// 函数名后的T: 定义泛型
// 参数和返回值后的T: 使用泛型
function genArray1<T> (n: Number, v: T): Array<T> {
let result = [];
for(let i=0; i<n; i++){
result[i] = v;
}
return result;
}
console.log('泛型 Generics');
console.log(genArray(3, 'x')); // [ 'x', 'x', 'x' ]
console.log(genArray1<Number>(3, 100)); // 显示指定泛型类型 [ 100, 100, 100 ]
console.log(genArray1(3, true)); // 没有显示置顶 ts能类型推论 [ true, true, true ]
// with Generics multi
function gen2<T, U> (a: [T, U]): Object{
return {
x: a[0],
y: a[1]
};
}
console.log(gen2(['abc', 123])); // { x: 'abc', y: 123 }
总结
- 是什么: [预先不指定]具体类型,[使用时指定]类型
- 定义: 函数名后定义泛型参数,
- 使用: 函数入参和返回值使用泛型参数
声明合并 declaration merging
- 是什么: 如果定义两个相同名字的函数、接口或类,那么它们会自动合并成一个类型
- 合并类型: 函数合并、 接口合并、 类合并
// 1. 函数合并
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string | undefined {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
// 个人理解 第3个reverse会覆盖前2个方法,调用时直接调用第3个reverse
console.log('reverse(123)=',reverse(123)) // reverse(123)= 321
console.log('reverse("abc")=',reverse("abc")) // reverse("abc")= cba
// [关于函数重载]
function overload(a){console.log('一个参数')}
function overload(a,b){console.log('两个参数')}
// 在支持重载的编程语言中,比如 java
overload(1); //一个参数
overload(1,2); //两个参数
// ❗ 在 JavaScript 中,不同的参数都调用第2个方法
overload(1); //两个参数
overload(1,2); //两个参数
// 2. 接口合并 注意,合并的属性可以重复,但是重复属性的类型必须相同
interface Alarm {price: number;}
interface Alarm {weight: number;}
// 相当于 interface Alarm {price: number; weight: number;}
let fireAlarm1:Alarm = {price:1000} // error
let fireAlarm2:Alarm = {weight:500} // error
let fireAlarm3:Alarm = {price:1000,weight:500} // ok
// 3. 类的合并 类的合并与接口的合并规则一致。