網站首頁 編程語言 正文
TypeScript 介紹
- TypeScript 是 JavaScript 的超集,提供了 JavaScript 的所有功能,并提供了可選的靜態類型、Mixin、類、接口和泛型等特性。
- TypeScript 的目標是通過其類型系統幫助及早發現錯誤并提高 JavaScript 開發效率。
- 通過 TypeScript 編譯器或 Babel 轉碼器轉譯為 JavaScript 代碼,可運行在任何瀏覽器,任何操作系統。
- 任何現有的 JavaScript 程序都可以運行在 TypeScript 環境中,并只對其中的 TypeScript 代碼進行編譯。
- 在完整保留 JavaScript 運行時行為的基礎上,通過引入靜態類型定義來提高代碼的可維護性,減少可能出現的 bug。
- 永遠不會改變 JavaScript 代碼的運行時行為,例如數字除以零等于 Infinity。這意味著,如果將代碼從 JavaScript 遷移到 TypeScript ,即使 TypeScript 認為代碼有類型錯誤,也可以保證以相同的方式運行。
- 對 JavaScript 類型進行了擴展,增加了例如
any
、unknown
、never
、void
。 - 一旦 TypeScript 的編譯器完成了檢查代碼的工作,它就會 擦除 類型以生成最終的“已編譯”代碼。這意味著一旦代碼被編譯,生成的普通 JS 代碼便沒有類型信息。這也意味著 TypeScript 絕不會根據它推斷的類型更改程序的 行為。最重要的是,盡管您可能會在編譯過程中看到類型錯誤,但類型系統自身與程序如何運行無關。
- 在較大型的項目中,可以在單獨的文件 tsconfig.json 中聲明 TypeScript 編譯器的配置,并細化地調整其工作方式、嚴格程度、以及將編譯后的文件存儲在何處。
函數
TypeScript 具有定義函數參數和返回值的特定語法。
- 函數返回值的類型可以明確定義。
function getTime(): number { return new Date().getTime(); } let time = getTime(); // let time: number console.log(time);
如果沒有定義返回類型,TypeScript 將嘗試通過返回的變量或表達式的類型來推斷它。
- 類型
void
可用于指示函數不返回任何值。
function printHello(): void { console.log('Hello!'); }
- 函數參數的類型與變量聲明的語法相似。
function multiply(a: number, b: number) { return a * b; }
如果沒有定義參數類型,TypeScript 將默認使用 any,除非額外的類型信息可用,如默認參數和類型別名。
- 默認情況下,TypeScript 會假定所有參數都是必需的,但它們可以顯式標記為可選。
// 這里的 `?` 運算符將參數 `c` 標記為可選 function add(a: number, b: number, c?: number) { return a + b + (c || 0); } console.log(add(2,5));
- 對于具有默認值的參數,默認值位于類型注釋之后。
function pow(value: number, exponent: number = 10) { return value ** exponent; }
TypeScript 還可以從默認值推斷類型。
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'.
- 命名參數遵循與普通參數相同的模式。
function divide({ dividend, divisor }: { dividend: number, divisor: number }) { return dividend / divisor; } console.log(divide({dividend: 10, divisor: 2}));
- 剩余參數可以像普通參數一樣類型化,但類型必須是數組,因為剩余參數始終是數組。
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));
- 函數類型可以與具有類型別名的函數分開指定。
type Negate = (value: number) => number; // 參數 value 自動從 Negate 類型被分配 number 類型 const negateFunction: Negate = (value) => value * -1; console.log(negateFunction(10));
- 函數重載是方法名字相同,而參數不同,返回類型可以相同也可以不同。
- 函數重載類型化定義了一個函數可以被調用的所有方式,在自動補全時會很有用,在自動補全中列出所有可能的重載記錄。
- 函數重載需要定義重載簽名(一個以上,定義函數的形參和返回類型,沒有函數體,不可調用)和一個實現簽名。
- 除了常規的函數之外,類中的方法也可以重載。
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.
在本例中,我們編寫了兩個重載:一個接受一個參數,另一個接受三個參數。前兩個簽名稱為重載簽名,但它們都不能用兩個參數調用。
在下面這個示例中,我們可以用字符串或數組調用它。但是,我們不能使用可能是字符串或數組的值調用它,因為 TypeScript 只能將函數調用解析為單個重載:
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.
因為兩個重載都有相同的參數計數和相同的返回類型,所以我們可以編寫一個非重載版本的函數:
function len(x: any[] | string) { return x.length; }
現在我們可以使用任意一種值調用它,所以如果可能,首選具有聯合類型的參數,而不是重載。
枚舉
枚舉是一個特殊的“類”,表示一組常量(不可更改的變量)。使用枚舉類型可以為一組數值賦予更加友好的名字。枚舉有兩種數據類型:string
和 numer
。
- 默認情況下,枚舉會將第一個值初始化為
0
,后面的值依次值加1
。
enum CardinalDirections { North, East, South, West }; let currentDirection: CardinalDirections = CardinalDirections.North; console.log(currentDirection); // '0' 因為 North 是第一個值 // currentDirection = 'North'; // Error: "North" is not assignable to type 'CardinalDirections'.
- 可以設置第一個枚舉的值的數字,并讓它自動遞增。
enum CardinalDirections { North = 1, East, South, West } console.log(CardinalDirections.North); // logs 1 console.log(CardinalDirections.West); // logs 4
- 可以為每個枚舉值分配唯一的數值,值將不會自動遞增。
enum StatusCodes { NotFound = 404, Success = 200, Accepted = 202, BadRequest = 400 }; console.log(StatusCodes.NotFound); // logs 404 console.log(StatusCodes.Success); // logs 200
-
string
類型比numer
類型枚舉更常見,因為它們的可讀性和目的性更強。
enum CardinalDirections { North = 'North', East = "East", South = "South", West = "West" }; console.log(CardinalDirections.North); // logs "North" console.log(CardinalDirections.West); // logs "West"
可以混合字符串和數字枚舉值,但不建議這樣做。
- 可以通過枚舉值來獲取枚舉名稱。
enum StatusCodes { NotFound = 404, Success = 200, Accepted = 202, BadRequest = 400 }; let s1 = StatusCodes[200]; // string | undefined console.log(s1); // Success
- 如果某個屬性的值是計算出來的,它后面的第一位成員必須初始化。
const value = 0; enum List { A = value, B = 2, // 必須初始化 C, }
聯合類型
聯合類型(Union Types)可以通過 |
運算符將變量設置多種類型,賦值時可以根據設置的類型來賦值。當一個值可以是多個單一類型時,可以使用聯合類型。例如當變量是 string
?或?number
時。
function printStatusCode(code: string | number) { console.log(`My status code is $[code].`) } printStatusCode(404); printStatusCode('404');
注意:使用聯合類型時,需要知道你的類型是什么,以避免類型錯誤:
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' }
在上述示例中,因為 toUpperCase()
是一個字符串方法,而數字無法訪問它。
類型別名和接口
TypeScript 允許類型與使用它們的變量分開定義。類型別名和接口允許在不同的變量之間輕松共享類型。
類型別名
- 就像我們使用了匿名對象類型一樣。
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 });
- 可以使用類型別名為任何類型命名,而不僅僅是對象類型。例如,類型別名可以命名聯合類型:
type ID = number | string;
- 類型別名可以定義指定區間具體的數值,該類型只能取定義的區間內的數值。
type Direction = 'center' | 'left' | 'right'; let d: Direction = ''; // Type '""' is not assignable to type 'Direction'.
- 類型別名可以指定模板字符串類型規則。
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';
接口
接口類似于類型別名,但是只適用于對象類型。
- 就像上面使用類型別名一樣,TypeScript 只關心我們傳遞給
printCoord
的值的結構——它是否具有預期的屬性。只關心類型的結構和功能,這就是我們將 TypeScript 稱為結構類型系統的原因。
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 });
- 接口的幾乎所有功能都可以在類型別名中使用,關鍵區別在于類型別名不能重新定義以添加新屬性,而接口始終是可擴展的。
type Window = { title: string } // Error: Duplicate identifier 'Window'. type Window = { ts: TypeScriptAPI } interface Window { title: string } interface Window { ts: TypeScriptAPI }
- 接口通過
extends
關鍵字可以繼承另一個接口、類、類型別名來擴展成員,支持多繼承,在extends
關鍵字之后用逗號分隔。
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 };
- 接口或類型別名中可以將數組的索引值和元素設置為不同類型。
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'.
交叉類型
接口允許我們通過擴展其他類型來構建新類型。TypeScript 還提供了另一種稱為交叉類型的結構,使用 &
運算符定義,主要用于組合現有的對象類型。
- 交叉類型包含了所需的所有類型的特性。
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
相交以生成一個包含 Colorful
和 Circle
的所有成員的新類型。
- 可以將多個接口類型合并成一個類型,實現等同于接口繼承的效果。
interface A { name: string; age: number; } interface B { name: string; height: string; } type Person = A & B; // 相當于求并集 const person: Person = { name: 'Tom', age: 18, height: '60kg' };
- 類型別名也可以與接口 交叉。
interface Animal { name: string } type Person = Animal & { age: number; }
- 類型別名可以通過交叉類型實現接口的繼承行為。
type Animal = { name: string } type Bear = Animal & { honey: boolean }
- 原始類型之間交叉類型為
never
,因為任何類型都不能滿足同時屬于多種原始類型。
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 類添加了類型和可見性修飾符。
- 類的成員(屬性和方法)使用類型注釋(類似于變量)進行類型化。
class Person { name: string; } const person = new Person(); person.name = "Jane";
- 類成員也可以被賦予影響可見性的特殊修飾符。TypeScript 中有三個主要的可見性修飾符:
-
public
-(默認)允許從任何地方訪問類成員 -
private
- 只允許從類內部訪問類成員 -
protected
- 允許從自身和繼承它的任何類訪問類成員
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 通過向參數添加可見性修飾符,可以在構造函數中定義類成員。
class Person { constructor(private name: string) {} getName(): string { return this.name; } } const person = new Person("Jane"); console.log(person.getName()); // Jane
- 與數組類似,
readonly
關鍵字可以防止類成員被更改,只讀屬性必須在聲明時或構造函數里被初始化,readonly
關鍵字也可以在構造函數中定義類成員。
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.
- 類通過
extends
關鍵字繼承另一個類,一個類只能繼承一個類;通過implements
關鍵字實現接口,一個類支持實現多個接口,在implements
關鍵字之后用逗號分隔。
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); } }
- 當一個類擴展另一個類時,它可以用相同的名稱重寫父類的成員。較新版本的 TypeScript 允許使用
override
關鍵字顯式標記,它可以幫助防止意外重寫不存在的方法。使用設置noImplicitOverride
可以強制在重寫時使用它。
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}]`; } }
- 抽象類允許它們用作其他類的基類,而無需實現其所有成員。通過使用
abstract
關鍵字定義抽象類,未實現的成員也需要使用abstract
關鍵字標識。抽象類不能直接實例化,因為它們沒有實現其所有成員。
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 支持通過
getters/setters
來截取對對象成員的訪問,有效地控制對對象成員的訪問。只帶有get
不帶有set
的存取器自動被推斷為 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); }
- 靜態成員存在于類本身上面而不是類的實例上。
class StaticMem { static num: number; static disp(): void { console.log("num 值為 " + StaticMem.num); } } StaticMem.num = 12; StaticMem.disp();
原文鏈接:https://juejin.cn/post/7193932637160308797
相關推薦
- 2023-03-21 C#中寫入和讀取TXT文件問題_C#教程
- 2022-10-10 Axios和Jquery實現文件上傳功能_jquery
- 2022-04-08 iOS實現簡單計算器功能_IOS
- 2022-10-21 C++?smart?pointer全面深入講解_C 語言
- 2022-11-15 Python中class內置方法__init__與__new__作用與區別解析_python
- 2022-06-07 Sphinx生成python文檔示例圖文解析_python
- 2022-01-13 封裝axios以及接口管理
- 2022-05-02 Numpy中創建數組的9種方式小結_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支