這篇文章將為大家詳細講解有關Typescript 類型檢查原理之Override怎么實現(xiàn),小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
我們提供的服務有:成都網站建設、網站設計、微信公眾號開發(fā)、網站優(yōu)化、網站認證、黃山區(qū)ssl等。為上千多家企事業(yè)單位解決了網站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的黃山區(qū)網站制作公司
首先,我們來看下這個修飾符的作用:被 override 標示的方法必須得在父類中存在,否則會報錯。
class Animal { getName() { return ''; } } class Dog extends Animal { override bak() { return 'wang'; } override getName() { return 'wang'; } }上面這段代碼會報錯:This member cannot have an 'override' modifier because it is not declared in the base class 'Animal'.就是說重寫的放在父類不存在,這樣能避免父類重構的時候把一些子類需要重寫的方法給去掉。

其實所有的修飾符,包括 override、public、static 等,在 parse 成 AST 后都是作為一個屬性存在的,這個 override 也是,我們通過 astexplorer.net 來查看一下。

可以看到 override 屬性為 true。這樣我們就可以通過這個屬性把該 class 的所有的需要 override 的 ClassMethod 過濾出來。
然后還可以拿到 superClass 的名字,從作用域中找到對應的聲明,然后遍歷 AST 找到它所聲明的所有 ClassMethod。
兩者對比一下,所有不在父類中的 ClassMethod 都需要報錯。
我們基于 babel 來做 parser 和分析,寫一個插件來做 override 的類型檢查。關于 babel 插件的基礎可以看小冊《babel 插件通關秘籍》。
開啟語法 typescript 插件來解析 ts 語法。
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,我們先搭一個基本的結構:
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')); } } });具體的檢查邏輯是拿到父類的所有方法名,拿到當前類的所有 override 方法名,然后做下過濾。
我們首先要拿到父類的 ast,通過名字從作用域中查找。
const superClass = path.node.superClass; if (superClass) { const superClassPath = path.scope.getBinding(superClass.name).path; }然后封裝一個方法來拿父類方法名,通過 path.traverse 來遍歷 ast,把收集到的方法名存到 state 中。
function getAllClassMethodNames(classDeclarationNodePath) { const state = { allSuperMethodNames: [] } classDeclarationNodePath.traverse({ ClassMethod(path) { state.allSuperMethodNames.push(path.get('key').toString()) } }); return state.allSuperMethodNames; }這樣就拿到了所有父類方法名。
之后需要拿到當前類的所有方法名并過濾出 override 為 true 且不在父類中的進行報錯。
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)) { // 報錯 } } } }); }報錯的部分使用 code frame 來創(chuàng)建友好的代碼打印格式,通過 Error.stackTraceLimit 設置為 0 去掉調用棧信息。
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 的類型檢查,整體代碼如下:
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;github 鏈接
我們用最開始的代碼來測試一下:
class Animal { getName() { return ''; } } class Dog extends Animal { override bak() { return 'wang'; } override getName() { return 'wang'; } }打印信息為:

正確的識別出了 bak 在父類不存在的錯誤。
至此,我們實現(xiàn)了 override 的類型檢查!
類型檢查情況很多,所以需要一個系列文章去講,這一篇我們來實現(xiàn) override 的類型檢查。
override 是 ts 4.3 加入的特性,帶有 override 修飾符的方法必須在父類中有對應的聲明,否則會報錯。
我們通過 babel 插件的方式實現(xiàn)了類型檢查,思路是從作用域取出父類的聲明,然后通過 path.traverse 拿到所有方法名,之后再取當前類的所有方法名,對于沒在父類中聲明并且?guī)в?override 修飾符的方法進行報錯。
關于“Typescript 類型檢查原理之Override怎么實現(xiàn)”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
網站名稱:Typescript類型檢查原理之Override怎么實現(xiàn)
標題鏈接:http://www.chinadenli.net/article22/gidijc.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網站、ChatGPT、品牌網站設計、企業(yè)建站、響應式網站、用戶體驗
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)