Typescript中interface自動化生成API文檔詳解
前言
最近在搞react組件庫,這兩天搞定了使用ast(抽象語法樹)去把interface轉(zhuǎn)為對象或者數(shù)組,這些數(shù)據(jù)就可以渲染為react組件的table或者markdown的table,啥意思呢,舉個例子:
UI層面
以下是interface的demo,被轉(zhuǎn)化
export interface TdAffixProps {
/**
* 指定滾動的容器。數(shù)據(jù)類型為 String 時,會被當(dāng)作選擇器處理,進行節(jié)點查詢。示例:'body' 或 () => document.body
* @default () => (() => window)
*/
container: any;
/**
* @desc 距離容器頂部達到指定距離后觸發(fā)固定
* @default 0
*/
offsetBottom?: number;
/**
* @desc 距離容器底部達到指定距離后觸發(fā)固定
* @default 0
*/
offsetTop?: number;
/**
* @desc 固釘定位層級,樣式默認(rèn)為 500
*/
zIndex?: number;
/**
* @desc 固定狀態(tài)發(fā)生變化時觸發(fā)
*/
onFixedChange?: (affixed: boolean, context: { top: number }) => void;
}轉(zhuǎn)化為類似:

數(shù)據(jù)層面
interface被轉(zhuǎn)化為數(shù)組,數(shù)組里的每一項如下,可以傳給table組件去渲染,當(dāng)然有人想渲染為markdown格式,那把下面的數(shù)組渲染為markdown的table就行了,沒啥難度。
{
"name": "TdAffixProps",
"data": [
{
"name": "container",
"type": "any",
"jsdoc": {
"kind": 24,
"description": "指定滾動的容器。數(shù)據(jù)類型為 String 時,會被當(dāng)作選擇器處理,進行節(jié)點查詢。示例:'body' 或 () => document.body",
"tags": [
{
"kind": 25,
"tagName": "default",
"text": "() => (() => window)"
}
]
}
},
{
"name": "offsetBottom",
"type": "number",
"isOptionnal": "?",
"jsdoc": {
"kind": 24,
"description": "",
"tags": [
{
"kind": 25,
"tagName": "desc",
"text": "距離容器頂部達到指定距離后觸發(fā)固定"
},
{
"kind": 25,
"tagName": "default",
"text": "0"
}
]
}
},
{
"name": "offsetTop",
"type": "number",
"isOptionnal": "?",
"jsdoc": {
"kind": 24,
"description": "",
"tags": [
{
"kind": 25,
"tagName": "desc",
"text": "距離容器底部達到指定距離后觸發(fā)固定"
},
{
"kind": 25,
"tagName": "default",
"text": "0"
}
]
}
},
{
"name": "zIndex",
"type": "number",
"isOptionnal": "?",
"jsdoc": {
"kind": 24,
"description": "",
"tags": [
{
"kind": 25,
"tagName": "desc",
"text": "固釘定位層級,樣式默認(rèn)為 500"
}
]
}
},
{
"name": "onFixedChange",
"type": "(affixed: boolean, context: { top: number }) => void",
"isOptionnal": "?",
"jsdoc": {
"kind": 24,
"description": "",
"tags": [
{
"kind": 25,
"tagName": "desc",
"text": "固定狀態(tài)發(fā)生變化時觸發(fā)"
}
]
}
}
]
}我們需要的數(shù)據(jù)結(jié)構(gòu)
上面可以看到,我們需要的數(shù)據(jù)結(jié)構(gòu)是
{
name: xxx, // interface的名字,
data: [
{
name: xx, // interface里每一項的屬性名
type: xx, // interface里每一項的類型
isOptionnal: xx, // 是否是可選項
jsDoc: {} // 后面細(xì)說
}
]
}簡單解釋一下jsdoc格式
JSDoc是一種文檔生成工具,可以用來為JavaScript代碼生成API文檔。它使用特殊的注釋格式來描述代碼中的類型、函數(shù)、變量等的用途、參數(shù)、返回值等信息。
例如,你可以在JavaScript代碼中使用如下的注釋來描述一個函數(shù):
/**
* 描述文字
* @default 0
*/
function sum(x, y) {
return x + y;
}這段注釋會被解析為:
{
"kind": 24, // 忽略
"description": "描述文字",
"tags": [
{
"kind": 25, // 忽略
"tagName": "default",
"text": 0
}
]
}AST解析技術(shù)選擇
為什么放棄babel
最開始我只知道babel,因為用webpack多了,不太了解ast相關(guān)的前端庫,然后很正常的這樣使用了,發(fā)現(xiàn)了問題:
const parser = require("@babel/parser")
const traverse = require("@babel/traverse").default
const generate = require('@babel/generator').default
const fs = require("fs")
fs.readFile('./type.ts', { encoding: 'utf-8' }, function (err, data) {
if (err) throw err;
const result = [];
const ast = parser.parse(data, {
sourceType: "unambiguous",
plugins: ["typescript"]
});
traverse(ast, {
TSInterfaceDeclaration(path) {
path.traverse({
TSPropertySignature(path) {
console.log(path.node.key.name);
console.log(path.node.leadingComments?.[0]?.value);
},
});
}
});
});比如number這個類型在上述打印節(jié)點的時候的類型是TSNumberKeyword,但是我拿到TSNumberKeyword不是目的,我要number,這個咋辦,
你說簡單啊,做個映射
{
TSNumberKeyword: "number"
}好,我知道簡單的映射可以,但是還有function類型,我咋映射,我需要還原的嘛,然后我想到了直接用generator把類型片段還原,但是總感覺有點low。
其次,我沒法直接獲得jsdoc的類型,因為注釋本質(zhì)上就是字符串,然后自己去折騰為jsdoc格式。
所以我去看了一下arco cli里的轉(zhuǎn)換使用到了ts-morph這個庫,發(fā)現(xiàn)這個庫在我這個需求下,是非常適合的,接下來介紹。
順便提一句,我的實現(xiàn)比字節(jié)團隊的arco cli要簡單非常非常多!
ts-morph
這個庫極大的緩解了不懂typescript繁瑣底層類型和方法的同學(xué),具體的方法和屬性真的也是挺多的。ts-morph是一個針對 Typescrpit/Javascript的AST處理庫,可用于瀏覽、修改TS/JS的AST。
關(guān)于ts-morph的詳細(xì)文檔,參見其官網(wǎng):ts-morph.com/。
下面是我實現(xiàn)的基本思路(可以把里面的函數(shù)抽取為中間件,這樣更好維護,目前懶得改了,類型沒認(rèn)真寫,大家可以在我的基礎(chǔ)上自己封裝適合自己業(yè)務(wù)的東西,思路還是很清晰的),后續(xù)會把它抽成一個單獨的庫給自己的react組件庫使用。
以下代碼說白了就一個簡單函數(shù),arco官方的cli工具雖然代碼也就200行的樣子,但是復(fù)雜度比我這個高很多。
自動化生成代碼
import { Project } from "ts-morph";
const internalProject = new Project({
tsConfigFilePath: "./tsconfig.json",
});
const sourceFile = internalProject.getSourceFile("./type.ts");
const interfaces = sourceFile!.getInterfaces();
const result:any[] = [];
interfaces.forEach((inter_face)=>{
result.push({
name: '',
data: []
});
const index = result.length - 1;
result[index].name = inter_face.getName();
inter_face.getProperties().forEach((v) => {
result[index].data.push({
name: v.getName(),
type: v.getTypeNode()?.getText(),
isOptionnal: v.getQuestionTokenNode()?.getText(),
jsdoc:v.getJsDocs().map((jsDoc)=>{
return (jsDoc.getStructure())
})[0]
});
});
})
console.log(result);總結(jié)
到此這篇關(guān)于Typescript中interface自動化生成API文檔的文章就介紹到這了,更多相關(guān)Typescript自動化生成API文檔內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解TypeScript中type與interface的區(qū)別
- typeScript?核心基礎(chǔ)之接口interface
- typescript中type和interface的區(qū)別有哪些
- TypeScript中的interface與type實戰(zhàn)
- TypeScript中type和interface的區(qū)別及注意事項
- Typescript中 type 與 interface 的區(qū)別說明總結(jié)
- Vue 3 TypeScript 接口Interface使用示例詳解
- TypeScript接口interface的高級用法詳解
- 解讀Typescript中interface和type的用法及區(qū)別
- TypeScript中type與interface的使用和區(qū)別
相關(guān)文章
javascript實現(xiàn)獲取指定精度的上傳文件的大小簡單實例
下面小編就為大家?guī)硪黄猨avascript實現(xiàn)獲取指定精度的上傳文件的大小簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
JavaScript中不同標(biāo)簽頁間通信的常見方式小結(jié)
在瀏覽器中,不同標(biāo)簽頁之間進行通信是一個常見的需求,本文介紹了JavaScript中不同標(biāo)簽頁間通信的常見方式,包括BroadcastChannel、localStorage、SharedWorker和window.postMessage+iframe,并詳細(xì)介紹了每種方法的實現(xiàn)和適用場景,需要的朋友可以參考下2025-05-05
PhantomJS快速入門教程(服務(wù)器端的 JavaScript API 的 WebKit)
Phantom JS是一個服務(wù)器端的 JavaScript API 的 WebKit。其支持各種Web標(biāo)準(zhǔn): DOM 處理, CSS 選擇器, JSON, Canvas, 和 SVG2015-08-08
javascript實現(xiàn)修改微信分享的標(biāo)題內(nèi)容等
這篇文章主要介紹了javascript實現(xiàn)修改微信分享的標(biāo)題內(nèi)容等,需要的朋友可以參考下2014-12-12
js獲取json中key所對應(yīng)的value值的簡單方法
下面小編就為大家?guī)硪黄猨s獲取json中key所對應(yīng)的value值的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03
JavaScript實現(xiàn)網(wǎng)頁截圖功能
這篇文章主要介紹了JavaScript實現(xiàn)網(wǎng)頁截圖功能,本文介紹了2款實現(xiàn)JavaScript截圖的開源組件,一個是Canvas2Image,一個是html2canvas,需要的朋友可以參考下2014-10-10
面試判斷元素是否在可視區(qū)域中IntersectionObserver詳解
這篇文章主要為大家介紹了判斷元素是否在可視區(qū)域中IntersectionObserver面試詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03

