目錄
安裝TypeScript
全局環境下安裝 tsc 命令
npm install -g typescript
hello.ts文件
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = 'Tom';
console.log(sayHello(user));
然後執行
tsc hello.ts
這時候會生成一個編譯好的文件 hello.js
function sayHello(person) {
return 'Hello, ' + person;
}
var user = 'Tom';
console.log(sayHello(user));
TypeScript 只會進行靜態檢查,如果發現有錯誤,編譯的時候就會報錯。
TypeScript 編譯的時候即使報錯了,還是會生成編譯結果,我們仍然可以使用這個編譯之後的文件。
基礎使用
原始數據類型在ts中的應用
原始數據類型包括:布爾值、數值、字符串、null、undefined、ES6的Symbol、ES11的BigInt
boolean
let isDone: boolean = false;
注意,使用構造函數 Boolean 創造的對象不是布爾值:
let createdByNewBoolean: boolean = new Boolean(1);
// Type 'Boolean' is not assignable to type 'boolean'.
// 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
事實上 new Boolean() / Boolean()返回的是一個 Boolean 對象:
let createdByNewBoolean: Boolean = new Boolean(1);
let createdByBoolean: boolean = Boolean(1);
其他基本類型(除了 null 和 undefined)一樣
number
let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
// ES6 中的二進制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八進制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;
string
let myName: string = 'Tom';
let myAge: number = 25;
// 模板字符串
let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`;
編譯爲:
var myName = 'Tom';
var myAge = 25;
// 模板字符串
var sentence = "Hello, my name is " + myName + ".\nI'll be " + (myAge + 1) + " years old next month.";
空值(Void)
function alertName(): void {
alert('My name is Tom');
}
//表示沒有任何返回值的函數
let unusable: void = undefined;
//聲明一個 void 類型的變量只能將它賦值爲 undefined 和 null
Null 和 Undefined
let u: undefined = undefined;
let n: null = null;
undefined 和 null 是所有類型的子類型。也就是說 undefined 類型的變量,可以賦值給 number 類型的變量:
// 這樣不會報錯
let num: number = undefined;
而 void 類型的變量不能賦值給 number 類型的變量:
let u: void;
let u: void;
let num: number = u;
// Type 'void' is not assignable to type 'number'.
任意值(Any)
允許被賦值爲任意類型
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
任意值的屬性和方法
在任意值上訪問任何屬性都是允許的:
let anyThing: any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);
也允許調用任何方法:
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
可以認爲,聲明一個變量爲任意值之後,對它的任何操作,返回的內容的類型都是任意值。
變量如果在聲明的時候,未指定其類型且沒賦值,那麼它會被識別爲任意值類型:
let something;
something = 'seven';
something = 7;
something.setName('Tom');
類型推論
TypeScript 會在沒有明確的指定類型的時候推測出一個類型
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// index.ts(2,1): error TS2322: Type 'number' is not assignable to type 'string'.
如果定義的時候沒有賦值,不管之後有沒有賦值,都會被推斷成 any 類型而完全不被類型檢查
如果定義的時候賦值過,但沒指定類型,會推測出一個類型
聯合類型
聯合類型使用 | 分隔每個類型。
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
聯合類型的屬性或方法
當 TypeScript 不確定一個聯合類型的變量到底是哪個類型的時候,我們只能訪問此聯合類型的所有類型裏共有的屬性或方法
function getLength(something: string | number): number {
return something.length;
}
// index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.
上例中,length 不是 string 和 number 的共有屬性,所以會報錯。
訪問 string 和 number 的共有屬性是沒問題的:
function getString(something: string | number): string {
return something.toString();
}
聯合類型的變量在被賦值的時候,會根據類型推論的規則推斷出一個類型:
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
//推斷成了 string
console.log(myFavoriteNumber.length); // 5
myFavoriteNumber = 7;
//推斷成了 number
console.log(myFavoriteNumber.length); // 編譯時報錯
// index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.
對象的類型–接口(Interfaces)
基本例子
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
上面的例子中,我們定義了一個接口 Person,接着定義了一個變量 tom,它的類型是 Person。這樣,我們就約束了 tom 的形狀必須和接口 Person 一致。
定義的變量比接口少了一些屬性是不允許的:
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom'
};
// index.ts(6,5): error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
// Property 'age' is missing in type '{ name: string; }'.
多一些屬性也是不允許的:
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.
可見,賦值的時候,變量的形狀必須和接口的形狀保持一致。
可選屬性
可選屬性的含義是該屬性可以不存在。
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom'
};
這時仍然不允許添加未定義的屬性:
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.
任意屬性
允許有任意的屬性
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
使用 [propName: string] 定義了任意屬性取 string 類型的值。
需要注意的是,一旦定義了任意屬性,那麼確定屬性和可選屬性的類型都必須是它的類型的子集:
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Index signatures are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
上例中,任意屬性的值允許是 string,但是可選屬性 age 的值卻是 number,number 不是 string 的子屬性,所以報錯了。
另外,在報錯信息中可以看出,此時 { name: ‘Tom’, age: 25, gender: ‘male’ } 的類型被推斷成了 { [x: string]: string | number; name: string; age: number; gender: string; },這是聯合類型和接口的結合。
一個接口中只能定義一個任意屬性。如果接口中有多個類型的屬性,則可以在任意屬性中使用聯合類型:
interface Person {
name: string;
age?: number;
[propName: string]: string | number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
只讀屬性
有時候我們希望對象中的一些字段只能在創建的時候被賦值,那麼可以用 readonly 定義只讀屬性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
tom.id = 89757;
// index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
// Property 'id' is missing in type '{ name: string; gender: string; }'.
// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
上例中,報錯信息有兩處,第一處是在對 tom 進行賦值的時候,沒有給 id 賦值。
第二處是在給 tom.id 賦值的時候,由於它是隻讀屬性,所以報錯了。