這篇文章主要介紹了Typescript類(lèi)型檢查原理之Override如何實(shí)現(xiàn)的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇Typescript類(lèi)型檢查原理之Override如何實(shí)現(xiàn)文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
創(chuàng)新互聯(lián)專(zhuān)注于企業(yè)全網(wǎng)整合營(yíng)銷(xiāo)推廣、網(wǎng)站重做改版、云霄網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁(yè)面制作、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性?xún)r(jià)比高,為云霄等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。首先,我們來(lái)看下這個(gè)修飾符的作用:被 override 標(biāo)示的方法必須得在父類(lèi)中存在,否則會(huì)報(bào)錯(cuò)。
class Animal { getName() { return ''; } } class Dog extends Animal { override bak() { return 'wang'; } override getName() { return 'wang'; } }
上面這段代碼會(huì)報(bào)錯(cuò):This member cannot have an 'override' modifier because it is not declared in the base class 'Animal'.就是說(shuō)重寫(xiě)的放在父類(lèi)不存在,這樣能避免父類(lèi)重構(gòu)的時(shí)候把一些子類(lèi)需要重寫(xiě)的方法給去掉。
其實(shí)所有的修飾符,包括 override、public、static 等,在 parse 成 AST 后都是作為一個(gè)屬性存在的,這個(gè) override 也是,我們通過(guò) astexplorer.net 來(lái)查看一下。
可以看到 override 屬性為 true。這樣我們就可以通過(guò)這個(gè)屬性把該 class 的所有的需要 override 的 ClassMethod 過(guò)濾出來(lái)。
然后還可以拿到 superClass 的名字,從作用域中找到對(duì)應(yīng)的聲明,然后遍歷 AST 找到它所聲明的所有 ClassMethod。
兩者對(duì)比一下,所有不在父類(lèi)中的 ClassMethod 都需要報(bào)錯(cuò)。
我們基于 babel 來(lái)做 parser 和分析,寫(xiě)一個(gè)插件來(lái)做 override 的類(lèi)型檢查。
開(kāi)啟語(yǔ)法 typescript 插件來(lái)解析 ts 語(yǔ)法。
const { transformFromAstSync } = require('@babel/core'); const parser = require('@babel/parser'); const ast = parser.parse(sourceCode, { sourceType: 'unambiguous', plugins: ['typescript'] }); const { code } = transformFromAstSync(ast, sourceCode, { plugins: [overrideCheckerPlugin] });
插件要處理的是 ClassDeclaration,我們先搭一個(gè)基本的結(jié)構(gòu):
const { declare } = require('@babel/helper-plugin-utils'); const overrideCheckerPlugin = declare((api, options, dirname) => { api.assertVersion(7); return { pre(file) { file.set('errors', []); }, visitor: { ClassDeclaration(path, state) { const semanticErrors = state.file.get('errors'); //... state.file.set('errors', semanticErrors); } }, post(file) { console.log(file.get('errors')); } } });
具體的檢查邏輯是拿到父類(lèi)的所有方法名,拿到當(dāng)前類(lèi)的所有 override 方法名,然后做下過(guò)濾。
我們首先要拿到父類(lèi)的 ast,通過(guò)名字從作用域中查找。
const superClass = path.node.superClass; if (superClass) { const superClassPath = path.scope.getBinding(superClass.name).path; }
然后封裝一個(gè)方法來(lái)拿父類(lèi)方法名,通過(guò) path.traverse 來(lái)遍歷 ast,把收集到的方法名存到 state 中。
function getAllClassMethodNames(classDeclarationNodePath) { const state = { allSuperMethodNames: [] } classDeclarationNodePath.traverse({ ClassMethod(path) { state.allSuperMethodNames.push(path.get('key').toString()) } }); return state.allSuperMethodNames; }
這樣就拿到了所有父類(lèi)方法名。
之后需要拿到當(dāng)前類(lèi)的所有方法名并過(guò)濾出 override 為 true 且不在父類(lèi)中的進(jìn)行報(bào)錯(cuò)。
const superClass = path.node.superClass; if (superClass) { const superClassPath = path.scope.getBinding(superClass.name).path; const allMethodNames = getAllClassMethodNames(superClassPath); path.traverse({ ClassMethod(path) { if (path.node.override){ const methodName = path.get('key').toString(); const superClassName = superClassPath.get('id').toString(); if (!allMethodNames.includes(methodName)) { // 報(bào)錯(cuò) } } } }); }
報(bào)錯(cuò)的部分使用 code frame 來(lái)創(chuàng)建友好的代碼打印格式,通過(guò) Error.stackTraceLimit 設(shè)置為 0 去掉調(diào)用棧信息。
const tmp = Error.stackTraceLimit; Error.stackTraceLimit = 0; let errorMessage = `this member cannot have an 'override' modifier because it is not declared in the base class '${superClassName}'`; semanticErrors.push(path.get('key').buildCodeFrameError(errorMessage, Error)); Error.stackTraceLimit = tmp;
這樣,我們就完成了 override 的類(lèi)型檢查,整體代碼如下:
const { declare } = require('@babel/helper-plugin-utils'); function getAllClassMethodNames(classDeclarationNodePath) { const state = { allSuperMethodNames: [] } classDeclarationNodePath.traverse({ ClassMethod(path) { state.allSuperMethodNames.push(path.get('key').toString()) } }); return state.allSuperMethodNames; } const overrideCheckerPlugin = declare((api, options, dirname) => { api.assertVersion(7); return { pre(file) { file.set('errors', []); }, visitor: { ClassDeclaration(path, state) { const semanticErrors = state.file.get('errors'); const superClass = path.node.superClass; if (superClass) { const superClassPath = path.scope.getBinding(superClass.name).path; const allMethodNames = getAllClassMethodNames(superClassPath); path.traverse({ ClassMethod(path) { if (path.node.override){ const methodName = path.get('key').toString(); const superClassName = superClassPath.get('id').toString(); if (!allMethodNames.includes(methodName)) { const tmp = Error.stackTraceLimit; Error.stackTraceLimit = 0; let errorMessage = `this member cannot have an 'override' modifier because it is not declared in the base class '${superClassName}'`; semanticErrors.push(path.get('key').buildCodeFrameError(errorMessage, Error)); Error.stackTraceLimit = tmp; } } } }); } state.file.set('errors', semanticErrors); } }, post(file) { console.log(file.get('errors')); } } }); module.exports = overrideCheckerPlugin;
我們用最開(kāi)始的代碼來(lái)測(cè)試一下:
class Animal { getName() { return ''; } } class Dog extends Animal { override bak() { return 'wang'; } override getName() { return 'wang'; } }
打印信息為:
正確的識(shí)別出了 bak 在父類(lèi)不存在的錯(cuò)誤。
關(guān)于“Typescript類(lèi)型檢查原理之Override如何實(shí)現(xiàn)”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“Typescript類(lèi)型檢查原理之Override如何實(shí)現(xiàn)”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道。
當(dāng)前標(biāo)題:Typescript類(lèi)型檢查原理之Override如何實(shí)現(xiàn)-創(chuàng)新互聯(lián)
新聞來(lái)源:http://vcdvsql.cn/article22/cccicc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容