TypeScript(二) 常見數(shù)據(jù)類型

image-20200528172415100

注: symbol 為ES6中新增類型

類型

  1. string /boolean /number
// 字符串:支持es6 拼接
let sport:string = '足球'
let hobby:string;
hobby = `我愛${sport}` // 支持es6 拼接 ``
console.log( hobby)

// 布爾值
let choice:boolean = false

// 數(shù)值: 和JavaScript一樣,TypeScript里的所有數(shù)字都是浮點(diǎn)數(shù)。支持二進(jìn)制、八進(jìn)制、十進(jìn)制、十六進(jìn)制、整數(shù)和小數(shù)(整數(shù)可以算進(jìn)十進(jìn)制)、NaN(非數(shù)字)、Infinity(無窮大)
let binNum:number = 0b110 // 二進(jìn)制
let octNum:number = 0o6 // 八進(jìn)制
let num:number =  6// 十進(jìn)制
let hexNum:number = 0x6 // 十六進(jìn)制
let maxNum:number = Infinity // 無窮大
let isNaNum:number = NaN // 非數(shù)值

注意:
(1)這里的string是小寫的,和String是有區(qū)別的
(2)使用構(gòu)造函數(shù)(Boolean 、StringNumber)創(chuàng)造的對(duì)象并不是布爾值,而是返回一個(gè)對(duì)象。直接調(diào)用Boolean() 則返回一個(gè)布爾值,常用于將一個(gè)值強(qiáng)制轉(zhuǎn)換為boolean類型,在此我以構(gòu)造函數(shù) Boolean 為例:

let isBoolean:boolean = new Boolean(1) // 報(bào)錯(cuò)'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
let isBoolean:boolean = Boolean(1) // true
  1. array 數(shù)組
  • 特點(diǎn)
    元素類型限制,長度不限制

方式1:類型[]

let array: number[] = [1, 2, 3, 4];

數(shù)組的一些方法的參數(shù)也會(huì)根據(jù)數(shù)組在定義時(shí)約定的類型進(jìn)行限制:

array.push('2');
// 報(bào)錯(cuò):Argument of type 'string' is not assignable to parameter of type 'number'

方式2:Array<類型>
(Array Generic) 數(shù)組泛型表示數(shù)組

let array: Array<number> = [1, 2, 3, 4];

自己寫數(shù)組泛型

方式3:接口(不推薦)
數(shù)組的索引就是 number 類型的 0,1,2,3..., JS 中數(shù)組是一類特殊的對(duì)象,特殊在數(shù)組的鍵(索引)是數(shù)值類型
MyArray 接口模擬原生的數(shù)組接口,并使用 [n: number]來作為索引簽名類型。

interface MyArray<T> {
  [index:number]: T
}
const testArray: MyArray<string> = ["1", "2", '3']
const testArray2: MyArray<number> = [1, 2, 3]

類數(shù)組:
類數(shù)組不是數(shù)組,使用數(shù)組的類型會(huì)報(bào)錯(cuò)

function add() {
    let args: number[] = arguments;
}
// 報(bào)錯(cuò):Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 26 more.

arguments 為類數(shù)組,應(yīng)該使用下面這種方式定義類型

function sum() {
    let args: {
        [index: number]: number;
        length: number;
        callee: Function;
    } = arguments;
}

其實(shí)常用的類數(shù)組都有自己的接口定義,如 IArguments, NodeList, HTMLCollection 等

function add() {
    let args: IArguments = arguments;
}
  1. tuple 元組
  • 語法

let 元組名:[類型1,類型2,類型3] = [值1, 值2,值3]

  • 使用
let tup1:[number, string, boolean] = [1, '3', true]

當(dāng)直接對(duì)元組中的變量進(jìn)行初始化的時(shí)候,變量的數(shù)量及變量對(duì)應(yīng)的類型必須與類型指定一致 ,否則報(bào)錯(cuò)

let tup1:[number, string, boolean] = [1, '3', true]
let tup2:[number, string, boolean] = [1, '3'] // Property '2' is missing in type '[number, string]' but required in type '[number, string, boolean]'.
let tup3:[number, string] = [1, 3] // Type 'number' is not assignable to type 'string'.

需要注意元祖的越界問題,雖然可以越界添加元素,但是不能越界訪問,強(qiáng)烈不建議這么使用,而且越界的元素的類型會(huì)被限制為元組中每個(gè)類型的聯(lián)合類型:

let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);
// Argument of type 'boolean' is not assignable to parameter of type 'string | number'
let tup4:[string, number] = ['1', 3]
tup3[0] = 'Tom'
tup3.push('apple')
console.log(tup3) // ["Tom", 3, "apple"]
console.log(tup3[2]) // Tuple type '[string, number]' of length '2' has no element at index '2'
  • 特點(diǎn)

長度限制,每個(gè)元素的類型限制,但不同元素類型可不同
其實(shí),可以和數(shù)組進(jìn)行對(duì)比理解:
數(shù)組是合并了相同類型的對(duì)象,而元組(Tuple)則是合并了不同類型的對(duì)象,且類型和數(shù)量已定

  1. enum 枚舉
  • 語法

enum 枚舉名{
枚舉項(xiàng)1 = 值1,
枚舉項(xiàng)2 = 值2 ...
}

注:枚舉項(xiàng)名稱一般由英文和數(shù)字組成,值一般用數(shù)字,默認(rèn)為0,1,2...

  • 使用

    默認(rèn)情況下是從0開始為元素編號(hào)

enum gender1 {
  male,
  female,
  unkown
}
console.log(gender1.male) // 0

也可以手動(dòng)的部分指定成員的數(shù)值或全部,后面的成員一次加1

enum gender2 {
  male,
  female = 2.5,
  unkown
}
console.log(gender2.male) // 0
console.log(gender2.unkown) // 3.5
  • 特點(diǎn)
    長度限制,每個(gè)元素的類型限制,但不同元素類型可不同
    可以理解為:定了元素類型和數(shù)量的數(shù)組,但多個(gè)元素類型可不同
  1. any 任意類型
    一般來說,如果一個(gè)變量賦值為某個(gè)類型,在賦值過程中是不允許改變類型的,但是any 類型除外,允許被賦值為任意類型。

    any類型 一般用在不清楚變量的類型的情況。 在這種情況下,不想讓類型檢查器對(duì)這些值進(jìn)行檢查。 就可以使用 any類型來標(biāo)記這些變量

  • 語法

let 變量名: any;

用來表示允許賦值為任意類型。

  • 使用
let anyThing1:any
anyThing1 = 'dd'
anyThing1 = 123

let anyThing2: any[] = [1, true]
anyThing2.push('222')
anyThing2[1] = undefined
console.log(anyThing2) // [1, undefined, "222"]

如果變量在聲明的時(shí)候未指定其類型,那么它會(huì)被識(shí)別為任意值類型:

let something;  // 等同于var something:any;
something = 'seven';
something = 7;
console.log(something); // 7
  1. void

沒有任何類型,從一定角度可以認(rèn)為void類型與any類型相反。但是在寫代碼的過程中一般不會(huì)單獨(dú)聲明一個(gè)void類型的變量,因?yàn)槠渲荒苜x值undefinednull,意義不大

let unusable: void = undefined;

void一般用在當(dāng)一個(gè)函數(shù)沒有返回值時(shí),設(shè)置返回值類型為 void

function sayHi(): void {
    console.log("Hi,everyone");
}
  1. null和undefined

undefinednull 都有自己的類型,分別為undefinednull 。但是這并沒有多大意義。

let undefType:undefined = undefined
let nullType:null = null

默認(rèn)情況下nullundefined是所有類型的子類型。 就是說你可以把 nullundefined賦值給其他類型的變量,但是如果設(shè)置了--strictNullChecks 嚴(yán)格的空校驗(yàn) ,nullundefined只能賦值給void和自身。 在寫代碼的過程中建議開啟空校驗(yàn)。 如果某個(gè)變量的類型可能為 numbernullundefined,建議使用聯(lián)合類型number | null | undefined

  1. never類型

表示永不存在的值的類型,一般用作拋出異?;驘o限循環(huán)的函數(shù)返回類型。

function test():never{
    while (true){
        ...
    }
}
function test2():never{
    throw new Error('Error');
}

never 類型是ts中的底部類型,是所有類型的子類型,因此可以賦值給任何類型變量

let cat:string = test()
  1. 聯(lián)合類型

在實(shí)際寫代碼的過程中,有時(shí)候定義的變量的類型可能是多種的,因此聯(lián)合類型便派上用場了。

  • 語法

let 變量名:類型1|類型2... = 值

  • 使用
let info:string|null|number;
info = 22
info = '你好嗎'
info = null

let infoArr:(string|number)[];
infoArr = [12, 'sad', 222]

當(dāng)不確定變量是哪個(gè)類型的時(shí)候,只能訪問此聯(lián)合類型的所有類型里共有的屬性或方法

let temp:(string|number|boolean);
console.log(temp.length) // Property 'length' does not exist on type 'number'.

9.交叉類型
類似于接口繼承,用于組合多個(gè)類型為一個(gè)類型(常用于對(duì)象類型)

interface Person { name: string }
interface People { sex: string }
type PersonMan = Person & People

相當(dāng)于:

type PersonMan  = {name: string, sex: string }

當(dāng)交叉的類型里有相同屬性時(shí)

   interface Person {
      name: string;
      title: string | number;
    }
    interface People {
      name: number;
      sex: string;
      title: string;
    }
    type PersonMan = Person & People;
    let dan: PersonMan = {
      name: 'ww', // name 報(bào)錯(cuò):Type 'string' is not assignable to type 'never'.
      sex: 'girl',
      title: 'title',
    };

name 類型推導(dǎo)結(jié)果是 never,因?yàn)椴淮嬖谝粋€(gè)值既是 string 又是 number 的。
title 類型推導(dǎo)結(jié)果是 string

總結(jié):
交叉類型算的是 2 個(gè)類型的 并集。就是雙方都有的東西才能合并到一起,不一樣的將會(huì)被排除
如果排除到最后都沒有相同的東西,那么就會(huì)變 never 類型(即該類型不存在)
內(nèi)置類型(string,number,boolean,unio 聯(lián)合類型)之間可以使用 &

  1. 映射類型
    參考
    映射類型是指基于現(xiàn)有類型產(chǎn)生新的類型
    通過遍歷語法拷貝原有類型 在拷貝類型的基礎(chǔ)上進(jìn)行修改從而產(chǎn)生新的類型
    語法:
{[P in K]: T} 

Partial 將每個(gè)屬性轉(zhuǎn)換為可選屬性

type Partial<T> = {
    [P in keyof T]?: T[P];
}
type PersonPartial = Partial<Person>;

Readonly 將每個(gè)屬性轉(zhuǎn)換為只讀屬性

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
}
type ReadonlyPerson = Readonly<Person>;

Pick 選取一組屬性指定新類型

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
}
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Pick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Exclude 去除交集,返回剩余的部分

type Exclude<T, U> = T extends U ? never : T
interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 };

const obj2: Required<Props> = { a: 5 };
Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'

Nullable 轉(zhuǎn)換為舊類型和null的聯(lián)合類型

type Nullable<T> = { 
  [P in keyof T]: T[P] | null 
}
type NullablePerson = Nullable<Person>;

Omit 適用于鍵值對(duì)對(duì)象的Exclude,去除類型中包含的鍵值對(duì)

type Omit = Pick<T, Exclude<keyof T, K>>
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = Omit<Todo, "description">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

Required 將每個(gè)屬性轉(zhuǎn)換為必選屬性

type Required<T> = {
  [P in keyof T]-?: T[P]
}
interface Props {
  a?: number;
  b?: string;
}

const obj: Props = { a: 5 };

const obj2: Required<Props> = { a: 5 };
  1. 接口
interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

接口一般首字母大寫。
注意:定義的變量比接口多或者少了一些屬性是不允許的:

可選屬性

interface Person {
    name: string;
    age?: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

建議:書寫的時(shí)候可選屬性建議放在最后

任意屬性

interface Person {
    name: string;
    age?: number;
    [key: string]: any;
}

let tom: Person = {
    name: 'Tom',
    gender: 'male'
};

注意:一旦定義了任意屬性,那么確定屬性和可選屬性的類型都必須是它的類型的子集

interface Person {
    name: string;
    age?: number;
    [key: string]: string;
}

let tom: Person = {
    name: 'Tom',
    age: 25,
    gender: 'male'
};

// 報(bào)錯(cuò):Property 'age' of type 'number' is not assignable to 'string' index type 'string'.

一個(gè)接口中只能定義一個(gè)任意屬性。如果接口中有多個(gè)類型的屬性,則可以在任意屬性中使用聯(lián)合類型:

interface Person {
    name: string;
    age?: number;
    [key: string]: string | number;
}

建議:實(shí)際開發(fā)中不要使用過多的任意類型,使用到什么屬性就把對(duì)應(yīng)的類型添加到接口里即可。

只讀屬性
如果只希望對(duì)象中的一些字段只能在創(chuàng)建的時(shí)候被賦值,那么可以用 readonly 定義只讀屬性:


// interface Person {
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {
    id: 89757,
    name: 'Tom',
    gender: 'male'
};

tom.id = 9527;

// 報(bào)錯(cuò):Cannot assign to 'id' because it is a read-only property.
  1. 字符串字面量
    字符串字面量類型用來約束取值只能是某幾個(gè)字符串中的一個(gè)。
type EventNames = 'click' | 'scroll' | 'mousemove';
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容