轉(zhuǎn)發(fā)
TypeScript基礎入門之高級類型的交叉類型和聯(lián)合類型
項目實踐倉庫
https://github.com/durban89/typescript_demo.git
tag: 1.4.2
為了保證后面的學習演示需要安裝下ts-node,這樣后面的每個操作都能直接運行看到輸出的結(jié)果。
npm install -D ts-node
后面自己在練習的時候可以這樣使用
npx ts-node 腳本路徑
高級類型
交叉類型(Intersection Types)
交叉類型是將多個類型合并為一個類型。 這讓我們可以把現(xiàn)有的多種類型疊加到一起成為一種類型,它包含了所需的所有類型的特性。 例如, Person & Serializable & Loggable同時是 Person 和 Serializable 和 Loggable。 就是說這個類型的對象同時擁有了這三種類型的成員。您將主要看到用于mixins的交集類型和其他不適合經(jīng)典面向?qū)ο竽>叩母拍?。(在JavaScript中有很多這些?。┻@是一個簡單的例子,展示了如何創(chuàng)建mixin:
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U>{}
for (let id in first) {
(<any>result)[id] = (<any>first)[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<any>result)[id] = (<any>second)[id];
}
}
return result
}
class AdvancedTypesClass {
constructor(public name: string){}
}
interface LoggerInterface {
log(): void;
}
class AdvancedTypesLoggerClass implements LoggerInterface {
log(): void {
console.log('console logging');
}
}
var logger = new AdvancedTypesLoggerClass();
var extend1 = extend(new AdvancedTypesClass("string"), new AdvancedTypesLoggerClass());
var e = extend1.name;
console.log(e);
extend1.log();
編譯運行,注意這里要編譯運行,我使用ts-node已經(jīng)不能運行成功了??赡苁悄睦锱渲玫挠袉栴},具體步驟如下。
tsc ./src/advanced_types_1.ts
$ node ./src/advanced_types_1.js
string
console logging
聯(lián)合類型(Union Types)
聯(lián)合類型與交叉類型很有關聯(lián),但是使用上卻完全不同。 偶爾你會遇到這種情況,一個代碼庫希望傳入 number或 string類型的參數(shù)。 例如下面的函數(shù):
/**
* 為給定的字符串左側(cè)添加"padding"
* 如果"padding"是一個字符串,則添加將字符串添加到給定字符串的左側(cè)
* 如果"padding"是一個數(shù)字,則添加padding個數(shù)量的空格到給定字符串的左側(cè)
*/
function padLeft(value: string, padding: any) {
if (typeof padding === 'string') {
return padding + value;
}
if (typeof padding === 'number') {
return Array(padding + 1).join(' ') + value;
}
throw new Error(`Excepted string or number, got ${padding}`);
}
console.log("|" + padLeft("string", 4) + "|");
console.log("|" + padLeft("string", "a") + "|");
編譯并運行后得到如下結(jié)果
$ tsc ./src/advanced_types_1.ts && node ./src/advanced_types_1.js
| string|
|astring|
padLeft有一個問題,就是padding這個參數(shù)是一個any類型,那就意味著我們可以在傳遞參數(shù)的時候,參數(shù)的類型可以是number或者是string,而TypeScript將會正常解析,
如果如下的方式調(diào)用,編譯的時候是可以正常解析的,但是運行的時候回報錯
padLeft("Hello world", true);
在傳統(tǒng)的面向?qū)ο笳Z言里,我們可能會將這兩種類型抽象成有層級的類型。 這么做顯然是非常清晰的,但同時也存在了過度設計。 padLeft原始版本的好處之一是允許我們傳入原始類型。 這樣做的話使用起來既簡單又方便。 如果我們就是想使用已經(jīng)存在的函數(shù)的話,這種新的方式就不適用了。除了any, 我們可以使用"聯(lián)合類型"做為padding的參數(shù),如下:
/**
* 為給定的字符串左側(cè)添加"padding"
* 如果"padding"是一個字符串,則添加將字符串添加到給定字符串的左側(cè)
* 如果"padding"是一個數(shù)字,則添加padding個數(shù)量的空格到給定字符串的左側(cè)
*/
function padLeft(value: string, padding: string | number) {
if (typeof padding === 'string') {
return padding + value;
}
if (typeof padding === 'number') {
return Array(padding + 1).join(' ') + value;
}
throw new Error(`Excepted string or number, got ${padding}`);
}
console.log("|" + padLeft("string", 4) + "|");
console.log("|" + padLeft("string", "a") + "|");
console.log("|" + padLeft("string", true) + "|");
編譯并運行后得到如下結(jié)果
$ tsc ./src/advanced_types_1.ts && node ./src/advanced_types_1.js
src/advanced_types_1.ts:65:37 - error TS2345: Argument of type 'true' is not assignable to parameter of type 'string | number'.
65 console.log("|" + padLeft("string", true) + "|");
從實例演示可以看出,當傳入一個boolean類型值的時候,在編輯的時候TypeScript就做出了判斷,表示boolean類型的參數(shù)不被支持
聯(lián)合類型表示一個值可以是幾種類型之一。 我們用豎線(|)分隔每個類型,所以 number | string | boolean表示一個值可以是 number, string,或 boolean。
如果一個值是聯(lián)合類型,我們只能訪問此聯(lián)合類型的所有類型里共有的成員,如下實例
interface Type1 {
func1(): void;
func2(): void;
}
interface Type2 {
func3(): void;
func2(): void;
}
class Type1Class implements Type1 {
func1(): void {
console.log('func1 run');
}
func2(): void {
console.log('func2 run');
}
}
class Type2Class implements Type2 {
func3(): void {
console.log('func1 run');
}
func2(): void {
console.log('func2 run');
}
}
function getSomeType(type: string): Type1Class | Type2Class {
if (type === '1') {
return new Type1Class();
}
if (type === '2') {
return new Type2Class();
}
throw new Error(`Excepted Type1Class or Type2Class, got ${type}`);
}
let type = getSomeType('1');
type.func2();
type.func1(); // 報錯
編譯并運行后得到如下結(jié)果
$ tsc ./src/advanced_types_1.ts
src/advanced_types_1.ts:111:6 - error TS2551: Property 'func1' does not exist on type 'Type1Class | Type2Class'. Did you mean 'func2'?
Property 'func1' does not exist on type 'Type2Class'.
111 type.func1();
這里的聯(lián)合類型可能有點復雜,但是你很容易就習慣了。 如果一個值的類型是 A | B,我們能夠 確定的是它包含了 A 和 B中共有的成員。 這個例子里, Type1Class具有一個func1成員。 我們不能確定一個 Type1Class | Type2Class類型的變量是否有func1方法。 如果變量在運行時是Type1Class類型,那么調(diào)用type.func1()就出錯了。
本實例結(jié)束實踐項目地址
https://github.com/durban89/typescript_demo.git
tag: 1.4.3