Exploring TypeScript Type Annotations - Data Typesgit
做者: zhilidali
歡迎來到 《探索 TypeScript 類型註解》 系列教程。
開篇咱們(從新)認識了 TypeScript,本篇探索 TypeScript 的原生數據類型。json
let bar: boolean = 'TS'; // Error: Type 'string' is not assignable to type 'boolean'.ts(2322)
Type Annotation 類型註解ui
: Type
。如 : boolean
。bar
爲布爾值。好處 :this
Type 'string' is not assignable to type 'boolean'
。bar
上時,會提示 let bar: boolean
。Primitive Typespa
boolean
、number
、string
、symbol
、undefined
null
void
、never
any
TypeScript 支持 JavaScript 的基礎類型rest
let tsBoo: boolean = false; let tsNum: number = 0x10; let tsStr: string = 'TS'; let tsSym: symbol = Symbol('TS'); let tsUnInit: undefined; let tsEmpty: null = { foo: 'Foo' }; // Error
TypeScript 還支持字面量類型,變量只能初始化爲相應的字面量類型值。code
// 字符串字面量 let ts: 'TS'; // 數值字面量 let one: 1 = 'TS'; // Error // 布爾字面量 let truthy: true;
void
void
標識函數沒有返回值(即返回 undefined)。
function tsVoid(): void { // 沒有返回值 }
never
never
標識函數不會 return。如拋出異常或生成器函數存在 while(true){}
。
function tsNever1(): never { throw new Error('Throw Exception or never return'); } function *tsNever2(): never { while(true) { // ... } }
undefined && null
undefined
、null
爲子類型,可賦給其它類型。在 tsconfig.json 中:
strictNullChecks
爲 false 時,undefined、null 可賦值給除 never
外的任意類型的變量。strictNullChecks
爲 true 時,undefined 只能賦值給 void
、any
類型的變量。let tsNum: number = undefined; // strictNullChecks 爲 true 時,Error let tsVoid: void = undefined; // Ok
void
void
做爲返回值類型時,可用其它類型替換。
let foo = function (): void { }; let bar = function (): number { return 1; } let baz = function (): string { return 'TS'; } foo = bar; // Ok,foo 的類型兼容 bar 的類型 foo = baz; // Ok,foo 的類型兼容 baz 的類型 bar = foo; // Error baz = foo; // Error
void VS. undefined
undefined
是void
的子類型。
- 在 JS 中,void 爲操做符,總返回 undefined; 而 undefined 在寬鬆模式下,可做變量。
- 在 TS 中,
void
做爲返回值類型時,可用其餘類型替換,而undefined
不行。
never
never
是全部類型的子類型, 可賦給任意類型。在 tsconfig.json 中:
strictNullChecks
爲 false 時,可直接賦給任意類型。strictNullChecks
爲 true 時,never
需在賦值後才能使用。let foo = function (): never { throw 'never' } // number 類型 let tsNum: number; // never 類型 let tsNever1 = foo(); let tsNever2: never; tsNum = tsNever1; // never 類型可賦值給 number 類型 tsNum = tsNever2; // `strictNullChecks` 爲 true 時,提示 Error。
any
TS 還增長了 any
類型,當不但願 TS 檢查時使用。
any
類型。any
類型能夠賦值給其它類型 (never
除外) 。let tsAny: any = 'any value'; let tsNum: number = tsAny; // any 類型能夠賦值給其它 tsAny = true; // 任意類型能夠賦值給 any 類型
任意類型也能夠賦值給
Object
類型 (一切皆對象),但會對其進行類型檢查
let foo: any = 1; let bar: Object = 1; foo.toFixed(); // 不會進行類型檢查 bar.toFixed(); // Error
TS 支持基本包裝類型Boolean
、Number
、String
、Symbol
。基本類型是相應的基本包裝類型的子類型。
// 基本包裝類型 Boolean let tsBool1: Boolean = new Boolean(); // 基本類型爲基本包裝類型的子類型 let tsBool2: Boolean = false;
字面量兼容性
let foo: "foo"; let bar = "foo"; // let bar: string foo = bar; // Error, 'foo' 不兼容 string
Reference Type
Date
、RegExp
、Error
、Function、Class 等類型tuple
、enum
類型{ prop: T }
描述對象類型的結構 (詳解見下篇)
let obj: { a: number } = { a: 1 }; obj.a = 2; // OK obj.b; // Error
注:object
描述的對象類型相似於{}
let obj1: {} = { a: 1 }; let obj2: object = { a: 1 }; obj1.a; // Error: Property 'a' does not exist on type '{}' obj2.a; // Error: Property 'a' does not exist on type 'object'
三種定義方式(後兩種詳解見下篇):
[]
_,即 T[]
Array<T>
ReadonlyArray<T>
interface
定義類型let tsArr1: string[] = ['foo']; // 數組泛型 let tsArr2: Array<string> = ['foo']; let readonlyArr: ReadonlyArray<string> = ['foo']; // 只讀數組 // 數值索引簽名 interface IdxType { [index: number]: string } let tsArr3: IdxType = ['foo'];
元組:已知固定元素及類型的數組
let tsTuple: [string, number] = ['foo', 1]; tsTuple[0] = 1; // Error tsTuple[2]; // Error,訪問索引以外的元素時會顯示錯誤
枚舉: 定義一組命名常量(枚舉成員只讀)
enum NumericEnum { Foo = 2, Bar, Baz }; /* 編譯器反向映射爲 var NumericEnum; (function (NumericEnum) { NumericEnum[NumericEnum["Foo"] = 2] = "Foo"; NumericEnum[NumericEnum["Bar"] = 3] = "Bar"; NumericEnum[NumericEnum["Baz"] = 4] = "Baz"; })(NumericEnum || (NumericEnum = {})); */ let num: NumericEnum = NumericEnum.Bar; // 3 let str: string = NumericEnum[3]; // Bar
enum StringEnum { No = 'NO', Yes = 'YES' } /* var StringEnum; (function (StringEnum) { StringEnum["No"] = "NO"; StringEnum["Yes"] = "YES"; })(StringEnum || (StringEnum = {})); */
enum HeterogeneousEnum { No = 0, Yes = "YES" } /* var HeterogeneousEnum; (function (HeterogeneousEnum) { HeterogeneousEnum[HeterogeneousEnum["No"] = 0] = "No"; HeterogeneousEnum["Yes"] = "YES"; })(HeterogeneousEnum || (HeterogeneousEnum = {})); */
let date: Date = new Date(); let reg: RegExp = /\.ts$/; let err: Error = new Error('error');
描述參數和返回值類型
(paramter: T): U
描述函數定義: (paramter: T) => U
描述函數變量// 定義函數聲明 function fn1(s: string): string { return s; } // 定義箭頭函數表達式 let fn2 = (s: string): string => s; // 函數變量 fn let fn3: (str: string) => string = fn2;
參數
foo: T
foo?: T
foo: T = value
...rest: T[]
let fn = ( s: string, // 必選參數 b: string = '', // 默認參數 c?: string, // 可選參數;位於必選參數後面 ...d: string[] // 剩餘參數;位於參數最後 ): string => s;
重載
// Overload function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
TypeScript 保留了 ES6 的語法,如下是分別用 ES6 和 TS 語法實現的類的建立和繼承:
// ES6 語法 class A { constructor(msg) { this.foo = msg; } getFoo() { return this.foo; } } class B extends A { constructor(msg) { super(msg); } getFoo() { return 'b' + super.getFoo(); } }
// TS 語法 class A { foo: string constructor(msg: string) { this.foo = msg; } getFoo() { return this.foo; } } class B extends A { constructor(msg: string) { super(msg); } getFoo() { return 'b' + super.getFoo(); } }
TS 在 ES6 基礎上對 class 增添了功能。
三種訪問修飾符:
public
在 TS 中,成員默認爲公有成員。private
私有成員只能在類中訪問,不能在類的外部訪問。protected
受保護的成員只能在類和子類中訪問。class A { public foo: string; // foo: string; private bar: string; protected baz: string; constructor(msg: string) { this.foo = msg; this.bar = msg; this.baz = msg; } getFoo() { return this.foo; } } class B extends A { constructor(msg: string) { super(msg); this.foo; // Ok this.bar; // Error: Property 'bar' is private and only accessible within class 'A'. this.baz; // Ok } getFoo() { return super.getFoo() + 'b'; } } const b = new B('str'); b.foo; // Ok b.bar; // Error: Property 'bar' is private and only accessible within class 'A'. b.baz; // Error: Property 'baz' is protected and only accessible within class 'A' and its subclasses
抽象類: 使用 abstract
定義抽象類和抽象類中的抽象方法
abstract class A { foo: string; constructor(msg: string) { this.foo = msg; } // 抽象方法不包含具體實現 abstract getFoo(): string; } class B extends A { // 必須被在派生類中實現抽象方法 getFoo() { return this.foo; } }
結語
本篇介紹了 TS 的原生數據類型,下一篇介紹如何自定義類型。
本做品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。