TypeScript全解:JS&TS

d.ts 文件的妙用

默認(rèn)情況下

*.d.ts 中的 type,interface 全局生效

// types.d.ts
type User = {
  name: string;
  age: number;
}
// main.ts
type A = User

但如果 *.d.ts 里有 import 或 export,則 User 只在當(dāng)前模塊生效

// types.d.ts
export type User = {
  name: string;
  age: number;
}
// main.ts
type A = User // TODO: 報(bào)錯(cuò)

但是加了import 或 export,還想全局生效怎么做?用 declare global

// types.d.ts
import x from 'vite'

type Local = string; // TODO: 注意這里不是全局的

declare global {
  interface User {
    name: string;
    age: number;
  }
}

d.ts 與 JS 文件結(jié)合

假設(shè)你已經(jīng)有如下 JS 文件

// x.js
window.addOne = function (n) {
  return n + 1
}

現(xiàn)在你想在你的 TS 文件中直接使用,雖然功能上可以,但是會(huì)有類型報(bào)錯(cuò)

// main.ts
const result = addOne(1) // TODO: 報(bào)錯(cuò),會(huì)提示你沒有這個(gè)函數(shù)

所以我們需要聲明一下

// global.d.ts
const addOne: (n: number) => number

// 等價(jià)于

type AddOne = (n: number) => number // 類型聲明
const addOne:AddOne // 變量聲明

這樣的弊端就在,如果你這里的類型寫錯(cuò)了,TS 也不能幫你檢測出來

但是實(shí)際場景,已經(jīng)沒有人寫這樣的代碼了,實(shí)際我們會(huì)遇到這樣的 JS 文件

// x.js
const add = (a, b) => a + b
export { add }

如果我們在 TS 文件中直接使用,會(huì)提示你這是一個(gè) JS 模塊,沒有類型,TS 不能直接使用

import { add } from './x'

所以我們一般會(huì)直接在同級(jí)目錄下新建相同名字的 *.d.ts

// x.d.ts

const add: (a: number, b: number) => number

export { add }

這樣 TS 就能幫你自動(dòng)建立關(guān)聯(lián)

d.ts 與 瀏覽器

當(dāng)我們有如下代碼的時(shí)候,這里的類型哪里來的呢?

const app = document.getElementById('app') // TODO: 這里的 app 直接就有類型了

是 tsconfig 里面加載好了的

// tsconfig.json
{
  "compilerOptions": {
    "lib": ["ESNext", "DOM"] // 這里的 DOM
  }
}

那這個(gè) DOM 相關(guān)的文件哪里來的呢?

是社區(qū)的程序員們一行一行寫好的,然后要么通過 github 上下載下來的,或從 npm 下載下來的,這樣我們才能很舒服的寫代碼,如果沒有這些文件,最基礎(chǔ)的 JS 代碼都沒有類型提示

*.d.ts + JS + React

正常我們是無法在 TS 中使用 React 的,因?yàn)?React 源碼是用的 flow,而不是 TS

import React from 'react' // TODO: 報(bào)錯(cuò)

但是我們可以通過 npm add -D @types/react,就能解決這個(gè)問題

所以說如果 node_modules/xxx 如果沒有提供類型聲明,就會(huì)去 node_modules/@types/xxx 去尋找

這也是 React 團(tuán)隊(duì)的解決思路,但是比不上 Vue 團(tuán)隊(duì)的方案好

*.d.ts + JS + Vue3

我們下載完后發(fā)現(xiàn)可以直接使用

import { createApp } from 'vue'

通過看包的源碼得:

原來是 vue 的 package.json 聲明了 types 屬性,所以我們就不用額外下載關(guān)聯(lián)了

小結(jié)

  • *.d.ts 的來歷
    • 源碼是 JS/Flow
      • 手寫 *.d.ts
    • 源碼是 TS
      • 自動(dòng)生成 *.d.ts
      • tsc -d x.ts
      • tsconfig

*.d.ts 與 Node.js

import * as fs from 'fs' // TODO: 報(bào)錯(cuò)

Node 也是一樣,需要安裝 @types/node,和 React 一樣,為什么還要單獨(dú)講呢?我們看一下源碼

可以看到里面有一堆的 reference,這些是干嘛用的呢?

  • reference lib -- 引入一個(gè) lib(有點(diǎn)像 tsconfig 里面的 lib 選項(xiàng))
  • reference path -- 引入一個(gè)相對(duì)路徑的文件
  • reference types="node" -- 引入一個(gè) types(有點(diǎn)像 tsconfig 里面的 types 選項(xiàng))

Node 為什么要用這么奇怪的語法呢?
因?yàn)樵缧┠?TS 出生的時(shí)候,那個(gè)時(shí)候還沒有 ES modules,所以 TS 不得不發(fā)明一種模塊引入語法

如果你的 tsconfig 里 types里沒有沒有包涵你想使用的類型,如:node,你可以這樣手動(dòng)添加

/// <reference types="node"
import * as fs from 'fs'

總結(jié)

給 JS 添加類型聲明的方式

  • 用 global.d.ts 聲明全局變量
  • 用 types.d.ts 聲明全局類型
    • 如果 import / export 了,就用 declare global
  • 用 同名.d.ts 聲明類型模塊
  • 用 @types/xxx 給 xxx 添加類型聲明
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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