TypeScript 的基本使用

安裝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 賦值的時候,由於它是隻讀屬性,所以報錯了。

數組的類型

參考博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章