TypeScript 高級(jí)數(shù)據(jù)類型實(shí)例詳解
TypeScript 介紹
- TypeScript 是 JavaScript 的超集,提供了 JavaScript 的所有功能,并提供了可選的靜態(tài)類型、Mixin、類、接口和泛型等特性。
- TypeScript 的目標(biāo)是通過(guò)其類型系統(tǒng)幫助及早發(fā)現(xiàn)錯(cuò)誤并提高 JavaScript 開(kāi)發(fā)效率。
- 通過(guò) TypeScript 編譯器或 Babel 轉(zhuǎn)碼器轉(zhuǎn)譯為 JavaScript 代碼,可運(yùn)行在任何瀏覽器,任何操作系統(tǒng)。
- 任何現(xiàn)有的 JavaScript 程序都可以運(yùn)行在 TypeScript 環(huán)境中,并只對(duì)其中的 TypeScript 代碼進(jìn)行編譯。
- 在完整保留 JavaScript 運(yùn)行時(shí)行為的基礎(chǔ)上,通過(guò)引入靜態(tài)類型定義來(lái)提高代碼的可維護(hù)性,減少可能出現(xiàn)的 bug。
- 永遠(yuǎn)不會(huì)改變 JavaScript 代碼的運(yùn)行時(shí)行為,例如數(shù)字除以零等于 Infinity。這意味著,如果將代碼從 JavaScript 遷移到 TypeScript ,即使 TypeScript 認(rèn)為代碼有類型錯(cuò)誤,也可以保證以相同的方式運(yùn)行。
- 對(duì) JavaScript 類型進(jìn)行了擴(kuò)展,增加了例如
any、unknown、never、void。 - 一旦 TypeScript 的編譯器完成了檢查代碼的工作,它就會(huì) 擦除 類型以生成最終的“已編譯”代碼。這意味著一旦代碼被編譯,生成的普通 JS 代碼便沒(méi)有類型信息。這也意味著 TypeScript 絕不會(huì)根據(jù)它推斷的類型更改程序的 行為。最重要的是,盡管您可能會(huì)在編譯過(guò)程中看到類型錯(cuò)誤,但類型系統(tǒng)自身與程序如何運(yùn)行無(wú)關(guān)。
- 在較大型的項(xiàng)目中,可以在單獨(dú)的文件 tsconfig.json 中聲明 TypeScript 編譯器的配置,并細(xì)化地調(diào)整其工作方式、嚴(yán)格程度、以及將編譯后的文件存儲(chǔ)在何處。
函數(shù)
TypeScript 具有定義函數(shù)參數(shù)和返回值的特定語(yǔ)法。
- 函數(shù)返回值的類型可以明確定義。
function getTime(): number {
return new Date().getTime();
}
let time = getTime(); // let time: number
console.log(time);
如果沒(méi)有定義返回類型,TypeScript 將嘗試通過(guò)返回的變量或表達(dá)式的類型來(lái)推斷它。
- 類型
void可用于指示函數(shù)不返回任何值。
function printHello(): void {
console.log('Hello!');
}
- 函數(shù)參數(shù)的類型與變量聲明的語(yǔ)法相似。
function multiply(a: number, b: number) {
return a * b;
}
如果沒(méi)有定義參數(shù)類型,TypeScript 將默認(rèn)使用 any,除非額外的類型信息可用,如默認(rèn)參數(shù)和類型別名。
- 默認(rèn)情況下,TypeScript 會(huì)假定所有參數(shù)都是必需的,但它們可以顯式標(biāo)記為可選。
// 這里的 `?` 運(yùn)算符將參數(shù) `c` 標(biāo)記為可選
function add(a: number, b: number, c?: number) {
return a + b + (c || 0);
}
console.log(add(2,5));
- 對(duì)于具有默認(rèn)值的參數(shù),默認(rèn)值位于類型注釋之后。
function pow(value: number, exponent: number = 10) {
return value ** exponent;
}
TypeScript 還可以從默認(rèn)值推斷類型。
function pow(value, exponent = 10) {
return value ** exponent;
}
console.log(pow(10, '2')); // Argument of type 'string' is not assignable to parameter of type 'number'.
- 命名參數(shù)遵循與普通參數(shù)相同的模式。
function divide({ dividend, divisor }: { dividend: number, divisor: number }) {
return dividend / divisor;
}
console.log(divide({dividend: 10, divisor: 2}));
- 剩余參數(shù)可以像普通參數(shù)一樣類型化,但類型必須是數(shù)組,因?yàn)槭S鄥?shù)始終是數(shù)組。
function add(a: number, b: number, ...rest: number[]) {
return a + b + rest.reduce((p, c) => p + c, 0);
}
console.log(add(10,10,10,10,10));
- 函數(shù)類型可以與具有類型別名的函數(shù)分開(kāi)指定。
type Negate = (value: number) => number; // 參數(shù) value 自動(dòng)從 Negate 類型被分配 number 類型 const negateFunction: Negate = (value) => value * -1; console.log(negateFunction(10));
- 函數(shù)重載是方法名字相同,而參數(shù)不同,返回類型可以相同也可以不同。
- 函數(shù)重載類型化定義了一個(gè)函數(shù)可以被調(diào)用的所有方式,在自動(dòng)補(bǔ)全時(shí)會(huì)很有用,在自動(dòng)補(bǔ)全中列出所有可能的重載記錄。
- 函數(shù)重載需要定義重載簽名(一個(gè)以上,定義函數(shù)的形參和返回類型,沒(méi)有函數(shù)體,不可調(diào)用)和一個(gè)實(shí)現(xiàn)簽名。
- 除了常規(guī)的函數(shù)之外,類中的方法也可以重載。
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3); // No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
在本例中,我們編寫了兩個(gè)重載:一個(gè)接受一個(gè)參數(shù),另一個(gè)接受三個(gè)參數(shù)。前兩個(gè)簽名稱為重載簽名,但它們都不能用兩個(gè)參數(shù)調(diào)用。
在下面這個(gè)示例中,我們可以用字符串或數(shù)組調(diào)用它。但是,我們不能使用可能是字符串或數(shù)組的值調(diào)用它,因?yàn)?TypeScript 只能將函數(shù)調(diào)用解析為單個(gè)重載:
function len(s: string): number;
function len(arr: any[]): number;
function len(x: any[] | string) {
return x.length;
}
len(""); // OK
len([0]); // OK
len(Math.random() > 0.5 ? "hello" : [0]); // No overload matches this call.
因?yàn)閮蓚€(gè)重載都有相同的參數(shù)計(jì)數(shù)和相同的返回類型,所以我們可以編寫一個(gè)非重載版本的函數(shù):
function len(x: any[] | string) {
return x.length;
}
現(xiàn)在我們可以使用任意一種值調(diào)用它,所以如果可能,首選具有聯(lián)合類型的參數(shù),而不是重載。
枚舉
枚舉是一個(gè)特殊的“類”,表示一組常量(不可更改的變量)。使用枚舉類型可以為一組數(shù)值賦予更加友好的名字。枚舉有兩種數(shù)據(jù)類型:string 和 numer。
- 默認(rèn)情況下,枚舉會(huì)將第一個(gè)值初始化為
0,后面的值依次值加1。
enum CardinalDirections {
North,
East,
South,
West
};
let currentDirection: CardinalDirections = CardinalDirections.North;
console.log(currentDirection); // '0' 因?yàn)?North 是第一個(gè)值
// currentDirection = 'North'; // Error: "North" is not assignable to type 'CardinalDirections'.
- 可以設(shè)置第一個(gè)枚舉的值的數(shù)字,并讓它自動(dòng)遞增。
enum CardinalDirections {
North = 1,
East,
South,
West
}
console.log(CardinalDirections.North); // logs 1
console.log(CardinalDirections.West); // logs 4
- 可以為每個(gè)枚舉值分配唯一的數(shù)值,值將不會(huì)自動(dòng)遞增。
enum StatusCodes {
NotFound = 404,
Success = 200,
Accepted = 202,
BadRequest = 400
};
console.log(StatusCodes.NotFound); // logs 404
console.log(StatusCodes.Success); // logs 200
string類型比numer類型枚舉更常見(jiàn),因?yàn)樗鼈兊目勺x性和目的性更強(qiáng)。
enum CardinalDirections {
North = 'North',
East = "East",
South = "South",
West = "West"
};
console.log(CardinalDirections.North); // logs "North"
console.log(CardinalDirections.West); // logs "West"
可以混合字符串和數(shù)字枚舉值,但不建議這樣做。
- 可以通過(guò)枚舉值來(lái)獲取枚舉名稱。
enum StatusCodes {
NotFound = 404,
Success = 200,
Accepted = 202,
BadRequest = 400
};
let s1 = StatusCodes[200]; // string | undefined
console.log(s1); // Success
- 如果某個(gè)屬性的值是計(jì)算出來(lái)的,它后面的第一位成員必須初始化。
const value = 0;
enum List {
A = value,
B = 2, // 必須初始化
C,
}
聯(lián)合類型
聯(lián)合類型(Union Types)可以通過(guò) | 運(yùn)算符將變量設(shè)置多種類型,賦值時(shí)可以根據(jù)設(shè)置的類型來(lái)賦值。當(dāng)一個(gè)值可以是多個(gè)單一類型時(shí),可以使用聯(lián)合類型。例如當(dāng)變量是 string 或 number 時(shí)。
function printStatusCode(code: string | number) {
console.log(`My status code is $[code].`)
}
printStatusCode(404);
printStatusCode('404');
注意:使用聯(lián)合類型時(shí),需要知道你的類型是什么,以避免類型錯(cuò)誤:
function printStatusCode(code: string | number) {
console.log(`My status code is ${code.toUpperCase()}.`); // error: Property 'toUpperCase' does not exist on type 'string | number'. Property 'toUpperCase' does not exist on type 'number'
}
在上述示例中,因?yàn)?toUpperCase() 是一個(gè)字符串方法,而數(shù)字無(wú)法訪問(wèn)它。
類型別名和接口
TypeScript 允許類型與使用它們的變量分開(kāi)定義。類型別名和接口允許在不同的變量之間輕松共享類型。
類型別名
- 就像我們使用了匿名對(duì)象類型一樣。
type Point = {
x: number;
y: number;
};
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
- 可以使用類型別名為任何類型命名,而不僅僅是對(duì)象類型。例如,類型別名可以命名聯(lián)合類型:
type ID = number | string;
- 類型別名可以定義指定區(qū)間具體的數(shù)值,該類型只能取定義的區(qū)間內(nèi)的數(shù)值。
type Direction = 'center' | 'left' | 'right'; let d: Direction = ''; // Type '""' is not assignable to type 'Direction'.
- 類型別名可以指定模板字符串類型規(guī)則。
type BooleanString = `${boolean}`;
const bool: BooleanString = '1'; // Type '"1"' is not assignable to type '"false" | "true"'.
type SerialNumber= `${number}.${number}`;
const id: SerialNumber= '1.2';
接口
接口類似于類型別名,但是只適用于對(duì)象類型。
- 就像上面使用類型別名一樣,TypeScript 只關(guān)心我們傳遞給
printCoord的值的結(jié)構(gòu)——它是否具有預(yù)期的屬性。只關(guān)心類型的結(jié)構(gòu)和功能,這就是我們將 TypeScript 稱為結(jié)構(gòu)類型系統(tǒng)的原因。
interface Point {
x: number;
y: number;
}
function printCoord(pt: Point) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 100, y: 100 });
- 接口的幾乎所有功能都可以在類型別名中使用,關(guān)鍵區(qū)別在于類型別名不能重新定義以添加新屬性,而接口始終是可擴(kuò)展的。
type Window = {
title: string
}
// Error: Duplicate identifier 'Window'.
type Window = {
ts: TypeScriptAPI
}
interface Window {
title: string
}
interface Window {
ts: TypeScriptAPI
}
- 接口通過(guò)
extends關(guān)鍵字可以繼承另一個(gè)接口、類、類型別名來(lái)擴(kuò)展成員,支持多繼承,在extends關(guān)鍵字之后用逗號(hào)分隔。
interface Show {
isShow: boolean;
}
type Graphic = {
name: string;
}
class Point {
x: number;
y: number;
}
interface Point3d extends Point, Graphic, Show {
z: number;
}
const point3d: Point3d = { x: 1, y: 2, z: 3, name: '1', isShow: true };
- 接口或類型別名中可以將數(shù)組的索引值和元素設(shè)置為不同類型。
interface i1 {
[index: number]: string
}
let list: i1 = ["0", "1", "2"];
// list2 = ["0", 1, "2"] // Type 'number' is not assignable to type 'string'.
interface i2 {
[index: string]: number
}
const list2: i2 = {};
list2["0"] = 0;
list2[1] = "1"; // Type 'string' is not assignable to type 'number'.
交叉類型
接口允許我們通過(guò)擴(kuò)展其他類型來(lái)構(gòu)建新類型。TypeScript 還提供了另一種稱為交叉類型的結(jié)構(gòu),使用 & 運(yùn)算符定義,主要用于組合現(xiàn)有的對(duì)象類型。
- 交叉類型包含了所需的所有類型的特性。
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
function draw(circle: Colorful & Circle) {
console.log(`Color was ${circle.color}`);
console.log(`Radius was ${circle.radius}`);
}
draw({ color: "blue", radius: 42 });
// 'raidus' does not exist in type 'Colorful & Circle'. Did you mean to write 'radius'?
draw({ color: "red", raidus: 42 });
在這里,我們將 Colorful 和 Circle 相交以生成一個(gè)包含 Colorful 和 Circle 的所有成員的新類型。
- 可以將多個(gè)接口類型合并成一個(gè)類型,實(shí)現(xiàn)等同于接口繼承的效果。
interface A {
name: string;
age: number;
}
interface B {
name: string;
height: string;
}
type Person = A & B; // 相當(dāng)于求并集
const person: Person = { name: 'Tom', age: 18, height: '60kg' };
- 類型別名也可以與接口 交叉。
interface Animal {
name: string
}
type Person = Animal & {
age: number;
}
- 類型別名可以通過(guò)交叉類型實(shí)現(xiàn)接口的繼承行為。
type Animal = {
name: string
}
type Bear = Animal & {
honey: boolean
}
- 原始類型之間交叉類型為
never,因?yàn)槿魏晤愋投疾荒軡M足同時(shí)屬于多種原始類型。
type Useless = string & number; // type Useless: never Useless = 1; // 'Useless' only refers to a type, but is being used as a value here.
類
TypeScript 向 JavaScript 類添加了類型和可見(jiàn)性修飾符。
- 類的成員(屬性和方法)使用類型注釋(類似于變量)進(jìn)行類型化。
class Person {
name: string;
}
const person = new Person();
person.name = "Jane";
- 類成員也可以被賦予影響可見(jiàn)性的特殊修飾符。TypeScript 中有三個(gè)主要的可見(jiàn)性修飾符:
public-(默認(rèn))允許從任何地方訪問(wèn)類成員private- 只允許從類內(nèi)部訪問(wèn)類成員protected- 允許從自身和繼承它的任何類訪問(wèn)類成員
class Person {
private name: string;
constructor(name: string) {
this.name = name;
}
getName(): string {
return this.name;
}
}
const person = new Person("Jane");
console.log(person.getName()); // person.name isn't accessible from outside the class since it's private
- TypeScript 通過(guò)向參數(shù)添加可見(jiàn)性修飾符,可以在構(gòu)造函數(shù)中定義類成員。
class Person {
constructor(private name: string) {}
getName(): string {
return this.name;
}
}
const person = new Person("Jane");
console.log(person.getName()); // Jane
- 與數(shù)組類似,
readonly關(guān)鍵字可以防止類成員被更改,只讀屬性必須在聲明時(shí)或構(gòu)造函數(shù)里被初始化,readonly關(guān)鍵字也可以在構(gòu)造函數(shù)中定義類成員。
class Person {
readonly name: string = 'Jane';
constructor(name?: string) {
if(name) this.name = name;
}
}
const person = new Person("a");
// person.name = ''; // Cannot assign to 'name' because it is a read-only property.
- 類通過(guò)
extends關(guān)鍵字繼承另一個(gè)類,一個(gè)類只能繼承一個(gè)類;通過(guò)implements關(guān)鍵字實(shí)現(xiàn)接口,一個(gè)類支持實(shí)現(xiàn)多個(gè)接口,在implements關(guān)鍵字之后用逗號(hào)分隔。
interface Shape {
getArea: () => number;
}
class Rectangle implements Shape {
constructor(protected readonly width: number, protected readonly height: number) {}
getArea(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
constructor(width: number) {
super(width, width);
}
}
- 當(dāng)一個(gè)類擴(kuò)展另一個(gè)類時(shí),它可以用相同的名稱重寫父類的成員。較新版本的 TypeScript 允許使用
override關(guān)鍵字顯式標(biāo)記,它可以幫助防止意外重寫不存在的方法。使用設(shè)置noImplicitOverride可以強(qiáng)制在重寫時(shí)使用它。
class Rectangle {
constructor(protected readonly width: number, protected readonly height: number) {}
toString(): string {
return `Rectangle[width=${this.width}, height=${this.height}]`;
}
}
class Square extends Rectangle {
constructor(width: number) {
super(width, width);
}
override toString(): string {
return `Square[width=${this.width}]`;
}
}
- 抽象類允許它們用作其他類的基類,而無(wú)需實(shí)現(xiàn)其所有成員。通過(guò)使用
abstract關(guān)鍵字定義抽象類,未實(shí)現(xiàn)的成員也需要使用abstract關(guān)鍵字標(biāo)識(shí)。抽象類不能直接實(shí)例化,因?yàn)樗鼈儧](méi)有實(shí)現(xiàn)其所有成員。
abstract class Polygon {
abstract getArea(): number;
toString(): string {
return `Polygon[area=${this.getArea()}]`;
}
}
class Rectangle extends Polygon {
constructor(protected readonly width: number, protected readonly height: number) {
super();
}
getArea(): number {
return this.width * this.height;
}
}
- TypeScript 支持通過(guò)
getters/setters來(lái)截取對(duì)對(duì)象成員的訪問(wèn),有效地控制對(duì)對(duì)象成員的訪問(wèn)。只帶有get不帶有set的存取器自動(dòng)被推斷為 readonly。
class Employee {
login: boolean;
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
console.log(this.login);
if (this.login === true) {
this._fullName = newName;
} else {
console.log("Error: Unauthorized update of employee!");
}
}
}
const employee = new Employee();
employee.login = true;
employee.fullName = "Bob Smith";
if (employee.fullName) {
console.log(employee.fullName);
}
- 靜態(tài)成員存在于類本身上面而不是類的實(shí)例上。
class StaticMem {
static num: number;
static disp(): void {
console.log("num 值為 " + StaticMem.num);
}
}
StaticMem.num = 12;
StaticMem.disp();以上就是TypeScript 高級(jí)數(shù)據(jù)類型實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript 高級(jí)數(shù)據(jù)類型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
數(shù)據(jù)結(jié)構(gòu)TypeScript之鏈表實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了數(shù)據(jù)結(jié)構(gòu)TypeScript之鏈表實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
詳解Typescript?嚴(yán)格模式有多嚴(yán)格
這篇文章主要為大家介紹了Typescript?嚴(yán)格模式有多嚴(yán)格實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
FastAdmin表單驗(yàn)證data-rule插件—Nice-validator的使用方法
FastAdmin的表單驗(yàn)證data-rule非常方便,也很炫酷,采用的Nice-validator是一款非常強(qiáng)大的表單驗(yàn)證插件,通過(guò)簡(jiǎn)單在元素上配置規(guī)則,即可達(dá)到驗(yàn)證的效果,怎么使用Nice-validator插件呢2023-09-09
TypeScript類型實(shí)現(xiàn)加減乘除詳解
這篇文章主要為大家介紹了TypeScript類型實(shí)現(xiàn)加減乘除示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
TypeScript數(shù)組實(shí)現(xiàn)棧與對(duì)象實(shí)現(xiàn)棧的區(qū)別詳解
這篇文章主要為大家介紹了TypeScript數(shù)組實(shí)現(xiàn)棧與對(duì)象實(shí)現(xiàn)棧的區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
TypeScript學(xué)習(xí)輕松玩轉(zhuǎn)類型操作
這篇文章主要為大家介紹了TypeScript學(xué)習(xí)輕松玩轉(zhuǎn)類型操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07

