TS基礎(chǔ)應(yīng)用 & Hook中的TS

說在前面

   本文難度偏中下,涉及到的點大多為如何在項目中合理應(yīng)用ts,小部分會涉及一些原理,受眾面較廣,有無TS基礎(chǔ)均可放心食用。
                        **>>>> 閱完本文,您可能會收獲到<<<<**
  1. 若您還不熟悉 TS,那本文可幫助您完成 TS 應(yīng)用部分的學(xué)習(xí),伴隨眾多 Demo 例來引導(dǎo)業(yè)務(wù)應(yīng)用;
  2. 若您比較熟悉 TS,那本文可當作復(fù)習(xí)文,帶您回顧知識,希望能在某些點引發(fā)您新發(fā)現(xiàn)和思考;
  3. 針對于 class 組件的 IState 和 IProps,類比 Hook 組件的部分寫法和思考;

??????TIPS:超好用的在線 TS 編輯器(諸多配置項可手動配置) 傳送門:TS 在線 ??????

一、什么是 TS

不扯晦澀的概念,通俗來說 TypeScript 就是 JavaScript 的超集,它具有可選的類型,并可以編譯為純 JavaScript 運行。(筆者一直就把 TypeScript 看作 JavaScript 的 Lint)那么問題來了,為什么 TS 一定要設(shè)計成靜態(tài)的? 或者換句話說,我們?yōu)槭裁葱枰?JavaScript 添加類型規(guī)范呢 ?

經(jīng)典自問自答環(huán)節(jié)——因為它可以解決一些 JS 尚未解決的痛點:

  1. JS 是動態(tài)類型的語言,這也意味著在實例化之前我們都不知道變量的類型,但是使用 TS 可以在運行前就避免經(jīng)典低級錯誤。 例: Uncaught TypeError:'xxx' is not a function

?? 典中典級別的錯誤??:

file
file
file

JS 就是這樣,只有在運行時發(fā)生了錯誤才告訴我有錯,但是當 TS 介入后:

file
file

好家伙!直接把問題在編輯器階段拋出,nice!

  1. 懶人狂歡。 規(guī)范方便,又不容易出錯,對于 VS Code,它能做的最多只是標示出有沒有這個屬性,但并不能精確的表明這個屬性是什么類型,但 TS 可以通過類型推導(dǎo)/反推導(dǎo)(說白話:如果您未明確編寫類型,則將使用類型推斷來推斷您正在使用的類型),從而完美優(yōu)化了代碼補全這一項:
file
file

第一個 Q&A——思考 :

那么我們還能想到在業(yè)務(wù)開發(fā)中 TS 解決了哪些 JS 的痛點呢?(提問)

回答,總結(jié),補充:
-對函數(shù)參數(shù)的類型限制;
-對數(shù)組和對象的類型限制,避免定義出錯 例如數(shù)據(jù)解構(gòu)復(fù)雜或較多時,
可能會出現(xiàn)數(shù)組定義錯誤 a = { }, if (a.length){ // xxxxx }
-let functionA = 'jiawen' // 實際上 let functionA: string = 'jiawen'

  1. 使我們的應(yīng)用代碼更易閱讀和維護,如果定義完善,可以通過類型大致明白參數(shù)的作用;

相信通過上述簡單的bug-demo,各位已對TS有了一個初步的重新認識
接下來的章節(jié)便正式介紹我們在業(yè)務(wù)開發(fā)過程中如何用好TS

二、怎么用 TS

 在業(yè)務(wù)中如何用TS/如何用好TS?這個問題其實和 " 在業(yè)務(wù)中怎么用好一個API " 是一樣的。首先要知道這個東西在干嘛,參數(shù)是什么,規(guī)則是什么,能夠接受有哪些擴展......等等。 簡而言之,擼它!
file

TS 常用類型歸納

通過對業(yè)務(wù)中常見的 TS 錯誤做出的一個綜合性總結(jié)歸納,希望 Demos 會對您有收獲

元語(primitives)之 string number boolean

  筆者把基本類型拆開的原因是: 不管是中文還是英文文檔,primitives/元語/元組 這幾個名詞都頻繁出鏡,筆者理解的白話:希望在類型約束定義時,使用的是字面量而不是內(nèi)置對象類型,官方文檔:
file
let a: string = 'jiawen';
let flag: boolean = false;
let num: number = 150

interface IState: {
  flag: boolean;
  name: string;
  num: number;
}

元組

// 元組類型表示已知元素數(shù)量和類型的數(shù)組,各元素的類型不必相同,但是對應(yīng)位置的類型需要相同。

let x: [string, number];
x = ['jiawen', 18];   // ok
x = [18, 'jiawen'];    // Erro
console.log(x[0]);    // jiawen

undefined null

let special: string = undefined
// 值得一提的是 undefined/null 是所有基本類型的子類,
// 所以它們可以任意賦值給其他已定義的類型,這也是為什么上述代碼不報錯的原因

object 和 { }

// object 表示的是常規(guī)的 Javascript對象類型,非基礎(chǔ)數(shù)據(jù)類型
const offDuty = (value: object) => {
  console.log("value is ",  value);
}

offDuty({ prop: 0}) // ok
offDuty(null) offDuty(undefined) // Error
offDuty(18) offDuty('offDuty') offDuty(false) // Error


//  {} 表示的是 非null / 非undefined 的任意類型
const offDuty = (value: {}) => {
  console.log("value is ", value);
}

offDuty({ prop: 0}) // ok
offDuty(null) offDuty(undefined) // Error
offDuty(18) offDuty('offDuty') offDuty(false) // ok
offDuty({ toString(){ return 333 } }) // ok

//  {} 和Object幾乎一致,區(qū)別是Object會對Object內(nèi)置的 toString/hasOwnPreperty 進行校驗
const offDuty = (value: Object) => {
  console.log("value is ",  value);
}

offDuty({ prop: 0}) // ok
offDuty(null) offDuty(undefined) // Error
offDuty(18) offDuty('offDuty') offDuty(false) // ok
offDuty({ toString(){ return 333 } }) // Error

如果需要一個對象類型,但對屬性沒有要求,建議使用 object 
{} 和 Object 表示的范圍太大,建議盡量不要使用

object of params

// 我們通常在業(yè)務(wù)中可多采用點狀對象函數(shù)(規(guī)定參數(shù)對象類型)

const offDuty = (value: { x: number; y: string }) => {
  console.log("x is ", value.x);
  console.log("y is ", value.y);
}

// 業(yè)務(wù)中一定會涉及到"可選屬性";先簡單介紹下方便快捷的“可選屬性”

const offDuty = (value: { x: number; y?: string }) => {
  console.log("必選屬性x ", value.x);
  console.log("可選屬性y ", value.y);
  console.log("可選屬性y的方法 ", value.y.toLocaleLowerCase());
}
offDuty({ x: 123, y: 'jiawen' })
offDuty({ x: 123 }) 

// 提問: 上述代碼有問題嗎?

答案:

// offDuty({ x: 123 }) 會導(dǎo)致結(jié)果報錯value.y.toLocaleLowerCase()
// Cannot read property 'toLocaleLowerCase' of undefined

方案1: 手動類型檢查
const offDuty = (value: { x: number; y?: string }) => {
    if (value.y !== undefined) {
            console.log("可能不存在的 ", value.y.toUpperCase());
  }
}
方案2:使用可選屬性 (推薦)
const offDuty = (value: { x: number; y?: string }) => {
  console.log("可能不存在的 ", value.y?.toLocaleLowerCase());
}

unknown 與 any

// unknown 可以表示任意類型,但它同時也告訴TS, 開發(fā)者對類型也是無法確定,做任何操作時需要慎重

let Jiaven: unknown

Jiaven.toFixed(1) // Error

if (typeof Jiaven=== 'number') {
  Jiaven.toFixed(1) // OK
}

當我們使用any類型的時候,any會逃離類型檢查,并且any類型的變量可以執(zhí)行任意操作,編譯時不會報錯

anyscript === javascript

注意:any 會增加了運行時出錯的風(fēng)險,不到萬不得已不要使用;

如果遇到想要表示【不知道什么類型】的場景,推薦優(yōu)先考慮 unknown

union 聯(lián)合類型

union也叫聯(lián)合類型,由兩個或多個其他類型組成,表示可能為任何一個的值,類型之間用 ' | '隔開

type dayOff = string | number | boolean

聯(lián)合類型的隱式推導(dǎo)可能會導(dǎo)致錯誤,遇到相關(guān)問題請參考語雀 code and tips —— 《TS的隱式推導(dǎo)》

.值得注意的是,如果訪問不共有的屬性的時候,會報錯,訪問共有屬性時不會.上個最直觀的demo

function dayOff (value: string | number): number {
    return value.length;
}
// number并不具備length,會報錯,解決方法:typeof value === 'string'

function dayOff (value: string | number): number {
    return value.toString();
}
// number和string都具備toString(),不會報錯

never

// never是其它類型(包括 null 和 undefined)的子類型,代表從不會出現(xiàn)的值。

// 那never在實際開發(fā)中到底有什么作用? 這里筆者原汁原味照搬尤雨溪的經(jīng)典解釋來做第一個例子

第一個例子,當你有一個 union type:

interface Foo {
  type: 'foo'
}

interface Bar {
  type: 'bar'
}

type All = Foo | Bar

在 switch 當中判斷 type,TS是可以收窄類型的 (discriminated union):

function handleValue(val: All) {
  switch (val.type) {
    case 'foo':
      // 這里 val 被收窄為 Foo
      break
    case 'bar':
      // val 在這里是 Bar
      break
    default:
      // val 在這里是 never
      const exhaustiveCheck: never = val
      break
  }
}

注意在 default 里面我們把被收窄為 never 的 val 賦值給一個顯式聲明為 never 的變量。
    
如果一切邏輯正確,那么這里應(yīng)該能夠編譯通過。但是假如后來有一天你的同事改了 All 的類型:

    type All = Foo | Bar | Baz

然而他忘記了在 handleValue 里面加上針對 Baz 的處理邏輯,
這個時候在 default branch 里面 val 會被收窄為 Baz,導(dǎo)致無法賦值給 never,產(chǎn)生一個編譯錯誤。
所以通過這個辦法,你可以確保 handleValue 總是窮盡 (exhaust) 了所有 All 的可能類型。

第二個用法  返回值為 never 的函數(shù)可以是拋出異常的情況
function error(message: string): never {
    throw new Error(message);
}

第三個用法 返回值為 never 的函數(shù)可以是無法被執(zhí)行到的終止點的情況
function loop(): never {
    while (true) {}
}

void

interface IProps {
  onOK: () => void
}
void 和 undefined 功能高度類似,但void表示對函數(shù)的返回值并不在意或該方法并無返回值

enum

筆者認為ts中的enum是一個很有趣的枚舉類型,它的底層就是number的實現(xiàn)

1.普通枚舉
enum Color {
  Red, 
  Green, 
  Blue
};
let c: Color = Color.Blue;
console.log(c); // 2

2.字符串枚舉
enum Color {
  Red = 'red', 
  Green = 'not red', 
};

3.異構(gòu)枚舉 / 有時也叫混合枚舉
enum Color {
  Red = 'red', 
  Num = 2, 
};
<第一個坑>

enum Color {
  A,         // 0
  B,         // 1
  C = 20,    // 20
  D,         // 21
  E = 100,   // 100
  F,         // 101
}

若初始化有部分賦值,那么后續(xù)成員的值為上一個成員的值加1
<第二個坑> 這個坑是第一個坑的延展,稍不仔細就會上當!

const getValue = () => {
  return 23
}

enum List {
  A = getValue(),
  B = 24,  // 此處必須要初始化值,不然編譯不通過
  C
}
console.log(List.A) // 23
console.log(List.B) // 24
console.log(List.C) // 25

如果某個屬性的值是計算出來的,那么它后面一位的成員必須要初始化值。
否則將會 Enum member must have initializer.

泛型

筆者理解的泛型很白話:先不指定具體類型,通過傳入的參數(shù)類型來得到具體類型
我們從下述的 filter-demo 入手,探索一下為什么一定需要泛型

  • 泛型的基礎(chǔ)樣式
function fun<T>(args: T): T {
    return args
}

如果沒接觸過,是不是會覺得有點懵? 沒關(guān)系!我們直接從業(yè)務(wù)角度深入——

1.剛開始的需求:過濾數(shù)字類型的數(shù)組

declare function filter(
    array: number[], 
  fn: (item: unknown) => boolean
) : number[];

2.產(chǎn)品改了需求:還要過濾一些字符串 string[] 

彳亍,那就利用函數(shù)的重載, 加一個聲明, 雖然笨了點,但是很好理解

declare function filter(
  array: string[],
  fn: (item: unknown) => boolean
): string[];

declare function filter(
  array: number[],
  fn: (item: unknown) => boolean
): number[];

3.產(chǎn)品又來了! 這次還要過濾 boolean[]、object[] ..........

這個時候如果還是選擇重載,將會大大提升工作量,代碼也會變得越來越累贅,這個時候泛型就出場了,
它從實現(xiàn)上來說更像是一種方法,通過你的傳參來定義類型,改造如下:

declare function filter<T>(
  array: T[],
  fn: (item: unknown) => boolean
): T[];

泛型中的<T>可以是任意,但是大部分偏好為 T、U、S 等,

當我們把泛型理解為一種方法實現(xiàn)后,那么我們便很自然的聯(lián)想到:方法有多個參數(shù)、默認值,泛型也可以

type Foo<T, U = string> = { // 多參數(shù)、默認值
  foo: Array<T> // 可以傳遞
  bar: U
}

type A = Foo<number> // type A = { foo: number[]; bar: string; }
type B = Foo<number, number> // type B = { foo: number[]; bar: number; }

既然是“函數(shù)”,那也會有“限制”,下文列舉一些稍微常見的約束

1. extends: 限制 T 必須至少是一個 XXX 的類型

type dayOff<T extends HTMLElement = HTMLElement> = {
   where: T,
   name: string
}
2. Readonly<T>: 構(gòu)造一個所有屬性為readonly,這意味著無法重新分配所構(gòu)造類型的屬性。

interface Eat {
  food: string;
}

const todo: Readonly<Eat> = {
  food: "meat beef milk",
};

todo.food = "no food"; // Cannot assign to 'title' because it is a read-only property.
3. Pick<T,K>: 從T中挑選出一些K屬性

interface Todo {
  name: string;
  job: string;
  work: boolean;


type TodoPreview = Pick<Todo, "name" | "work">;

const todo: TodoPreview = {
  name: "jiawen",
  work: true,
};
todo;
4. Omit<T, K>: 結(jié)合了 T 和 K 并忽略對象類型中 K 來構(gòu)造類型。

interface Todo {
  name: string;
  job: string;
  work: boolean;
}

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

const todo: TodoPreview = {
  name: "jiawen",
  job: 'job',
};

5.Record: 約束 定義鍵類型為 Keys、值類型為 Values 的對象類型。

enum Num {
  A = 10001,
  B = 10002,
  C = 10003
}

const NumMap: Record<Num, string> = { 
  [Num.A]: 'this is A',
  [Num.B]: 'this is B'
}
// 類型 "{ 10001: string; 10002: string; }" 中缺少屬性 "10003",
// 但類型 "Record<ErrorCodes, string>" 中需要該屬性,所以我們還可以通過Record來做全面性檢查

keyof 關(guān)鍵字可以用來獲取一個對象類型的所有 key 類型
type User = {
  id: string;
  name: string;
};

type UserKeys = keyof User;  // "id" | "name"

改造如下

type Record<K extends keyof any, T> = {
  [P in K]: T;
};
此時的 T 為 any;
還有一些不常用,但是很易懂的:

6. Extract<T, U>  從T,U中提取相同的類型

7. Partial<T>    所有屬性可選

type User = {
  id?: string,
  gender: 'male' | 'female'
}

type PartialUser =  Partial<User>  // { id?: string, gender?: 'male' | 'female'}
  
type Partial<T> = { [U in keyof T]?: T[U] }

8. Required<T>   所有屬性必須 << === >> 與Partial相反

type User = {
  id?: string,
  sex: 'male' | 'female'
}

type RequiredUser = Required<User> // { readonly id: string, readonly gender: 'male' | 'female'}

function showUserProfile (user: RequiredUser) {
  console.log(user.id) // 這時候就不需要再加?了
  console.log(user.sex)
}
type Required<T> = { [U in keyof T]-?: T[U] };   -? : 代表去掉?



三、TS 的一些須知

TS 的 type 和 interface

  • interface(接口) 只能聲明對象類型,支持聲明合并(可擴展)。
interface User {
  id: string
}
 
interface User {
  name: string
}
 
const user = {} as User
 
console.log(user.id);
console.log(user.name);

  • type(類型別名)不支持聲明合并 -- l 類型
type User = {
  id: string,
}

if (true) {
  type User = {
    name: string,
  }

  const user = {} as User;
  console.log(user.name);
  console.log(user.id) // 類型“User”上不存在屬性“id”。
}

file

????????????
type 和 interface 異同點總結(jié):

  1. 通常來講 type 更為通用,右側(cè)可以是任意類型,包括表達式運算,以及映射等;
  2. 凡是可用 interface 來定義的,type 也可;
  3. 擴展方式也不同,interface 可以用 extends 關(guān)鍵字進行擴展,或用來 implements 實現(xiàn)某個接口;
  4. 都可以用來描述一個對象或者函數(shù);
  5. type 可以聲明基本類型別名、聯(lián)合類型、元組類型,interface 不行;
  6. ?? 但如果你是在開發(fā)一個包,模塊,允許別人進行擴展就用 interface,如果需要定義基礎(chǔ)數(shù)據(jù)類型或者需要類型運算,使用 type。
  7. interface 可以被多次定義,并會被視作合并聲明,而 type 不支持;
  8. 導(dǎo)出方式不同,interface 支持同時聲明并默認導(dǎo)出,而 typetype 必須先聲明后導(dǎo)出;

TS 的腳本模式和模塊模式

Typescript 存在兩種模式,區(qū)分的邏輯是,文件內(nèi)容包不包含 import 或者 export 關(guān)鍵字

腳本模式(Script) 一個文件對應(yīng)一個 html 的 script 標簽,
模塊模式(Module)一個文件對應(yīng)一個 Typescript 的模塊。

腳本模式下,所有變量定義,類型聲明都是全局的,多個文件定義同一個變量會報錯,同名 interface 會進行合并;而模塊模式下,所有變量定義,類型聲明都是模塊內(nèi)有效的。

兩種模式在編寫類型聲明時也有區(qū)別,例如腳本模式下直接 declare var GlobalStore 即可為全局對象編寫聲明。

例子:

  • 腳本模式下直接 declare var GlobalStore 即可為全局對象編寫聲明。
GlobalStore.foo = "foo";
GlobalStore.bar = "bar"; // Error

declare var GlobalStore: {
  foo: string;
};
  • 模塊模式下,要為全局對象編寫聲明需要 declare global
GlobalStore.foo = "foo";
GlobalStore.bar = "bar";

declare global {
  var GlobalStore: {
    foo: string;
    bar: string;
  };
}

export {}; // export 關(guān)鍵字改變文件的模式

TS 的索引簽名

  • 索引簽名可以用來定義對象內(nèi)的屬性、值的類型,例如定義一個 React 組件,允許 Props 可以傳任意 key 為 string,value 為 number 的 props
interface Props {
  [key: string]: number
}

<Component count={1} /> // OK
<Component count={true} /> // Error
<Component count={'1'} /> // Error

TS 的類型鍵入

  • Typescript 允許像對象取屬性值一樣使用類型
type User = {
  userId: string
  friendList: {
    fristName: string
    lastName: string
  }[]
}

type UserIdType = User['userId'] // string
type FriendList = User['friendList'] // { fristName: string; lastName: string; }[]
type Friend = FriendList[number] // { fristName: string; lastName: string; }
  • 在上面的例子中,我們利用類型鍵入的功能從 User 類型中計算出了其他的幾種類型。FriendList[number]這里的 number 是關(guān)鍵字,用來取數(shù)組子項的類型。在元組中也可以使用字面量數(shù)字得到數(shù)組元素的類型。
type group = [number, string]
type First =  group[0] // number
type Second = group[1] // string

TS 的斷言

  • 類型斷言不是類型轉(zhuǎn)換,斷言成一個聯(lián)合類型中不存在的類型是不允許的
function getLength(value: string | number): number {
    if (value.length) {
        return value.length;
    } else {
        return value.toString().length;
    }
  
    // 這個問題在object of parmas已經(jīng)提及,不再贅述
  
    修改后:
    
    if ((<string>value).length) {
        return (<string>value).length;
    } else {
        return something.toString().length;
    }
}

斷言的兩種寫法

1. <類型>值:  <string>value

2. 或者 value as string

特別注意!!! 斷言成一個聯(lián)合類型中不存在的類型是不允許的

function toBoolean(something: string | number): boolean {
    return <boolean>something;
}
  • 非空斷言符 !

TypeScript 還具有一種特殊的語法,用于從類型中刪除 null 和 undefined 不進行任何顯式檢查。!在任何表達式之后寫入實際上是一個類型斷言,表明該值不是 null 或 undefined

function liveDangerously(x?: number | undefined | null) {
  // 推薦寫法
  console.log(x!.toFixed());
}

四、如何在 Hook 組件中使用 TS

usestate

  • useState 如果初始值不是 null/undefined 的話,是具備類型推導(dǎo)能力的,根據(jù)傳入的初始值推斷出類型;初始值是 null/undefined 的話則需要傳遞類型定義才能進行約束。一般情況下,還是推薦傳入類型(通過 useState 的第一個泛型參數(shù))。
// 這里ts可以推斷 value的類型并且能對setValue函數(shù)調(diào)用進行約束
const [value, setValue] = useState(0);

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

// 這里需要傳遞MyObject才能約束 value, setValue
// 所以我們一般情況下推薦傳入類型
const [value, setValue] = useState<MyObject>(null);

-----as unkonwn as unkownun

useEffect useLayoutEffect

  • 沒有返回值,無需類型傳遞和約束

useMemo useCallback

  • useMemo 無需傳遞類型, 根據(jù)函數(shù)的返回值就能推斷出類型。
  • useCallback 無需傳遞類型,根據(jù)函數(shù)的返回值就能推斷出類型。

但是注意函數(shù)的入?yún)⑿枰x類型,不然將會推斷為 any!

const value = 10;

const result = useMemo(() => value * 2, [value]); // 推斷出result是number類型

const multiplier = 2;
// 推斷出 (value: number) => number
// 注意函數(shù)入?yún)alue需要定義類型
const multiply = useCallback((value: number) => value * multiplier, [multiplier]);

useRef

  • useRef 傳非空初始值的時候可以推斷類型,同樣也可以通過傳入第一個泛型參數(shù)來定義類型,約束 ref.current 的類型。
1. 如果傳值為null
const MyInput = () => {
  const inputRef = useRef<HTMLInputElement>(null); // 這里約束inputRef是一個html元素
  return <input ref={inputRef} />
}
  
2. 如果不為null
const myNumberRef = useRef(0);  // 自動推斷出 myNumberRef.current 是number類型
myNumberRef.current += 1;

useContext

  • useContext 一般根據(jù)傳入的 Context 的值就可以推斷出返回值。一般無需顯示傳遞類型
type Theme = 'light' | 'dark';
// 我們在createContext就傳了類型了
const ThemeContext = createContext<Theme>('dark');

const App = () => (
  <ThemeContext.Provider value="dark">
    <MyComponent />
  </ThemeContext.Provider>
)

const MyComponent = () => {
    // useContext根據(jù)ThemeContext推斷出類型,這里不需要顯示傳
  const theme = useContext(ThemeContext);
  return <div>The theme is {theme}</div>;

五、關(guān)于 TS 的一些思考

1. 關(guān)于 TSC 如何把 TS 代碼轉(zhuǎn)換為 JS 代碼

這個部分比較冗長,后續(xù)可以單獨出一篇文章(2)來專門探索。
  • 不過,tsconfig.json 的部分常用的配置屬性表還是值得一提的
{
  "compilerOptions": {
    "noEmit": true, // 不輸出文件
    "allowUnreachableCode": true, // 不報告執(zhí)行不到的代碼錯誤。
    "allowUnusedLabels": false, // 不報告未使用的標簽錯誤
    "alwaysStrict": false, // 以嚴格模式解析并為每個源文件生成 "use strict"語句
    "baseUrl": ".", // 工作根目錄
    "lib": [ // 編譯過程中需要引入的庫文件的列表
      "es5",
      "es2015",
      "es2016",
      "es2017",
      "es2018",
      "dom"
    ]
    "experimentalDecorators": true, // 啟用實驗性的ES裝飾器
    "jsx": "react", // 在 .tsx文件里支持JSX
    "sourceMap": true, // 是否生成map文件
    "module": "commonjs", // 指定生成哪個模塊系統(tǒng)代碼
    "noImplicitAny": false, // 是否默認禁用 any
    "removeComments": true, // 是否移除注釋
    "types": [ //指定引入的類型聲明文件,默認是自動引入所有聲明文件,一旦指定該選項,則會禁用自動引入,改為只引入指定的類型聲明文件,如果指定空數(shù)組[]則不引用任何文件
      "node", // 引入 node 的類型聲明
    ],
    "paths": { // 指定模塊的路徑,和baseUrl有關(guān)聯(lián),和webpack中resolve.alias配置一樣
      "src": [ //指定后可以在文件之直接 import * from 'src';
        "./src"
      ],
    },
    "target": "ESNext", // 編譯的目標是什么版本的
    "outDir": "./dist", // 輸出目錄
    "declaration": true, // 是否自動創(chuàng)建類型聲明文件
    "declarationDir": "./lib", // 類型聲明文件的輸出目錄
    "allowJs": true, // 允許編譯javascript文件。
  },
  // 指定一個匹配列表(屬于自動指定該路徑下的所有ts相關(guān)文件)
  "include": [
    "src/**/*"
  ],
  // 指定一個排除列表(include的反向操作)
  "exclude": [
    "demo.ts"
  ],
  // 指定哪些文件使用該配置(屬于手動一個個指定文件)
  "files": [
    "demo.ts"
  ]
}

2. TS 泛型的底層實現(xiàn)

關(guān)于TS泛型進階篇 鏈接:[https://dtstack.yuque.com/rd-center/sm6war/wae3kg](https://dtstack.yuque.com/rd-center/sm6war/wae3kg)


這個部分比較復(fù)雜,筆者還需沉淀,歡迎各位直接留言或在文章中補充!!!

3. TS 泛型+類型反推在實際開發(fā)中的應(yīng)用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,087評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,207評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,603評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,813評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,364評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,110評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,305評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,532評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,033評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,268評論 2 375

推薦閱讀更多精彩內(nèi)容

  • ts的優(yōu)點:靜態(tài)編譯提示錯誤,強類型,接口和繼承,是js的超集,需要編譯后執(zhí)行 編譯 1、ts后綴建立文件后通過t...
    看到這朵小fa了么閱讀 468評論 0 0
  • 背景介紹 JavaScript創(chuàng)立20多年,已經(jīng)從當初只是為網(wǎng)頁添加瑣碎交互的小型腳本語言發(fā)展成應(yīng)用最廣泛的跨平臺...
    Eason_0cce閱讀 11,121評論 0 8
  • TypeScript是微軟開發(fā)的,基于類的面向?qū)ο缶幊蹋湮募?.ts 為后綴名; TypeScript是Jav...
    hellomyshadow閱讀 964評論 0 0
  • Vue3 基本全部使用 TypeScript 來進行重寫,盡管你可能覺得要學(xué)的東西越來越多了,但是作為程序員,如果...
    橙色流年閱讀 637評論 0 1
  • 一、TypeScript 概述 TypeScript 是微軟開發(fā)的自由和開源的編程語言; 是 JavaScript...
    yjtuuige閱讀 1,000評論 0 8