静态语言因其有类型而安全,TypeScript可以被认为是有类型的JavaScript,它的强大之处正是它强大的、精细的类型系统。
本文是该系列的基本篇,以下是正文
类型定义
基本数据类型(primitive type)
const nick: string = '';
const age: number = 1;
const binary: number = 0b1101;
const bit8: number = 0o1371;
const bit16: number = 0x1b2e;
const gmv: bigint = BigInt(Number.MAX_VALUE + 10);
const visible: boolean = true;
const uid: symbol = Symbol();
const say: Function = () => '';
const sayHello: () => string = () => 'Hello, world';
const obj: Object = {};
const obj2: Object = [1, 2];
const bookArray: string[] = ['JavaScript语言精粹', 'JavaScript忍者秘籍'];
const bookArray2: Array<String> = ['JavaScript语言精粹', 'JavaScript忍者秘籍'];
const container: [string, number, symbol] = [nick, age, uid];
enum Season{
Spring,
Summer,
Autumn,
Winter,
}
const s: Season = Season.Summer;
const arbitrarily: any = '';
const und: undefined = undefined;
const n: null = null;
never类型
这个类型在其他语言里比较少见,Java8里没有这个类型。
never代表永远不会发生的类型的值,和throw搭配使用,表示它后续的代码将unreachable,即不可到达。
never特性:
- 特性1: 通常在方法里和抛出异常throw搭配使用
- 特性2: never是所有类型的子类型,因此可以把never类型值赋给任意类型变量。
- 特性3: never没有子类型,因此所有类型的值都不能赋给never类型变量
对特性1,引用官方文档里的例子:
function error(message: string): never {
throw new Error(message);
}
function fail() {
return error("Something failed");
}
类、接口定义的类型
interface IAnimal {
getName(): string,
setHeight(height: number): void
}
interface IPerson extends IAnimal{
name: string
age: number
readonly height?: number
[pName: string]: any
getCountry?: (name: string) => string
}
class Person {
name: string;
age: number;
constructor(name: string, age: number){
this.name = name;
this.age = age;
}
run(){
console.log(`${this.name}`, ' is running');
}
}
const p2: Person = new Person('Android', 11);
上述和Java语言里的类型相似,接下来是TS特有的类型特性
交叉类型(intersection type): &
融合了多个类型
interface IAnyObj{
[propName: string]: any
}
function mixin<T extends IAnyObj, U extends IAnyObj>(first: T, second: U): T & U{
const result = <T & U>{};
for(let key in first){
(<T>result)[key] = first[key];
}
for(let key in second){
(<U>result)[key] = second[key];
}
return result;
}
联合类型(union types):|
是多个类型中的某一个,运行时一旦确定,就只能是其中这一个类型。
function handle(source: string[] | string): string[]{
const result: string[] = [];
if(typeof source === 'string'){
result.push(source);
}else{
for(let value of source){
result.push(value);
}
}
return result;
}
handle('test');
handle(['test1', 'test2']);
字面量类型(literal types)
值除了可以作为类型的值,还可以作为类型。在类型位置时,表示的是类型;写在类型值位置时,表示的就是类型值。通常和类型别名(type)联合使用。
const p3: { name: string, age: number } = {
name: 'TypeScript',
age: 5
};
const git: 'git' = 'git';
const bookCount: 10 = 10;
const spring: Season.Spring = Season.Spring;
字面量种类:
- 基本数据类型(常见的是字符串字面量类型
- 对象
别名类型: type
type JavaCoder = {
name: string,
age: number,
language: 'Java'
}
type Container<T> = { value: T };
别名类型不像上文提到的interface、class、字面量类型那样,它不是新建的类型,新建的是名称。定义一个新的名称和已有的类型对应起来,然后已有的类型就有了新的类型名字。
简单的综合应用
对交叉类型、联合类型,字面量类型,别名类型的综合的应用,如下
type CoderEnhance = JavaCoder & IAnyObj;
type SNtype = string | number;
type AttrWrapper = Array<string> | Array<number> | string | number;
type Season2 = 'Spring' | 'Summer' | 'Autumn' | 'Winter';
const s2: Season2 = 'Spring';
类型兼容&子类型
TS里的类型是结构化类型,也称鸭子类型(duck typing)。
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子
更确切地说,TypeScript的类型系统是结构类型系统(Structural type system),任两个以相同结构所描述的值的类型都是等价的。(与之相反的是,标明类型系统Nominative type system,表示类型若要相等,就必须具有相同的“名字”)
子类型
类型兼容(子类型)判断,可以用子集来描述;
一个类型代表一个集合,类型这个集合的元素是属性,如果一个类型A是类型B的子集,则有伪代码。
const a: A = new B()
函数套用集合的概念思考时,它的元素是入参。
类、字面量,接口套用集合的概念时,集合元素指的是它们的属性字段。类里,A是父类,B是子类;集合里A是B的子集,A是子集。这里注意,子集B对应代码的父类。
来一段示例代码:
interface IApple{
name: string,
}
class Apple {
name: string;
constructor(name: string){
this.name = name;
}
}
class Pear {
name: string;
constructor(name: string){
this.name = name;
}
}
class Banana {
name: string;
constructor(name: string){
this.name = name;
}
wash(){
console.log(`${this.name} is washing`);
}
}
const apple2: Apple = new Pear('some pear');
const apple3: IApple = new Pear('a pear');
const apple4: Apple = new Banana('a banana');
const load1 = (testA: string) => {}
const load2 = (testA: string, testB: number) => {}
const load3 = (a: string, b: number, c: string) => {}
console.log('That is', load1 == load2);
console.log('That is', load2 == load3);
type Table = {
name: string,
}
type Book = {
name: string,
width: number;
height: number;
}
const table: Table = new Person('JavaScript', 19);
联合类型的子类型
联合类型的子类型是什么?是联合类型内每个成员的子类型的联合类型。伪代码如下:
type Union = A | B | C;
type ChildrenUnion1 = A子类型 | B子类型 | C子类型
type ChildrenUnion2 = A子类型 | B子类型
type ChildrenUnion3 = A子类型 | C子类型
type ChildrenUnion4 = B子类型 | C子类型
type ChildrenUnion5 = A子类型
type ChildrenUnion6 = B子类型
type ChildrenUnion7 = C子类型
由上述伪代码可知,联合类型的子类型是其成员的子类型的所有无序组合。
字面量类型的子类型
基本数据类型的字面量类型的子类型是其本身。特别地,字符串字面量类型的子类型就是字符串本身。
字符串字面量类型的联合类型的子类型就是字符串值
type Season = 'spring' | 'summer' | 'autumn' | 'winter';
const s1: Season = 'spring';
const s2: Season = 'summer';
const s3: Season = 'autumn';
const s4: Season = 'winter';
小结
上述是TypeScript关于类型的基础使用,下篇我们来个综合实战。
TS类型系列延伸阅读:
Ethan Ruan:TypeScript类型系统(2/5)-基本篇综合应用zhuanlan.zhihu.com参考文献
- 掘金专栏:深入浅出TypeScript:从基础知识到类型编程
- TypeScript中文手册