成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Typescript 類型檢查原理之Override 是如何實現的

開發 前端
前段時間寫過一篇類型檢查的實現原理的文章,實現了簡單的賦值語句和函數調用的類型檢查。實際上類型檢查的情況特別多,一篇文章肯定寫不完,所以我準備用系列文章來講述各種類型檢查的實現原理,幫助大家更好的掌握 typescript。

[[403862]]

本文轉載自微信公眾號「神光的編程秘籍」,作者神說要有光 。轉載本文請聯系神光的編程秘籍公眾號。

前段時間寫過一篇類型檢查的實現原理的文章,實現了簡單的賦值語句和函數調用的類型檢查。實際上類型檢查的情況特別多,一篇文章肯定寫不完,所以我準備用系列文章來講述各種類型檢查的實現原理,幫助大家更好的掌握 typescript。

這一篇我們來實現 4.3 新增的 class 的 override 關鍵字的類型檢查。(源碼鏈接在后面)

override 修飾符是干嘛的

首先,我們來看下這個修飾符的作用:被 override 標示的方法必須得在父類中存在,否則會報錯。

  1. class Animal { 
  2.   getName() { return ''; } 
  3. class Dog extends Animal { 
  4.   override bak() { 
  5.     return 'wang'
  6.   } 
  7.   override getName() { 
  8.     return 'wang'
  9.   } 

上面這段代碼會報錯:This member cannot have an 'override' modifier because it is not declared in the base class 'Animal'.就是說重寫的放在父類不存在,這樣能避免父類重構的時候把一些子類需要重寫的方法給去掉。

如何實現 override 修飾符的類型檢查

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

可以看到 override 屬性為 true。這樣我們就可以通過這個屬性把該 class 的所有的需要 override 的 ClassMethod 過濾出來。

然后還可以拿到 superClass 的名字,從作用域中找到對應的聲明,然后遍歷 AST 找到它所聲明的所有 ClassMethod。

兩者對比一下,所有不在父類中的 ClassMethod 都需要報錯。

代碼實現

我們基于 babel 來做 parser 和分析,寫一個插件來做 override 的類型檢查。關于 babel 插件的基礎可以看小冊《babel 插件通關秘籍》。

開啟語法 typescript 插件來解析 ts 語法。

  1. const { transformFromAstSync } = require('@babel/core'); 
  2. const  parser = require('@babel/parser'); 
  3.  
  4. const ast = parser.parse(sourceCode, { 
  5.     sourceType: 'unambiguous'
  6.     plugins: ['typescript'
  7. }); 
  8.  
  9. const { code } = transformFromAstSync(ast, sourceCode, { 
  10.     plugins: [overrideCheckerPlugin] 
  11. }); 

插件要處理的是 ClassDeclaration,我們先搭一個基本的結構:

  1. const { declare } = require('@babel/helper-plugin-utils'); 
  2.  
  3. const overrideCheckerPlugin = declare((api, options, dirname) => { 
  4.     api.assertVersion(7); 
  5.  
  6.     return { 
  7.         pre(file) { 
  8.             file.set('errors', []); 
  9.         }, 
  10.         visitor: { 
  11.             ClassDeclaration(path, state) { 
  12.                 const semanticErrors = state.file.get('errors'); 
  13.                 //... 
  14.                 state.file.set('errors', semanticErrors); 
  15.             } 
  16.         }, 
  17.         post(file) { 
  18.             console.log(file.get('errors')); 
  19.         } 
  20.     } 
  21. }); 

具體的檢查邏輯是拿到父類的所有方法名,拿到當前類的所有 override 方法名,然后做下過濾。

我們首先要拿到父類的 ast,通過名字從作用域中查找。

  1. const superClass = path.node.superClass; 
  2. if (superClass) { 
  3.     const superClassPath = path.scope.getBinding(superClass.name).path; 

然后封裝一個方法來拿父類方法名,通過 path.traverse 來遍歷 ast,把收集到的方法名存到 state 中。

  1. function getAllClassMethodNames(classDeclarationNodePath) { 
  2.     const state = { 
  3.         allSuperMethodNames: [] 
  4.     } 
  5.     classDeclarationNodePath.traverse({ 
  6.         ClassMethod(path) { 
  7.             state.allSuperMethodNames.push(path.get('key').toString()) 
  8.         } 
  9.     }); 
  10.     return state.allSuperMethodNames; 

這樣就拿到了所有父類方法名。

之后需要拿到當前類的所有方法名并過濾出 override 為 true 且不在父類中的進行報錯。

  1. const superClass = path.node.superClass; 
  2. if (superClass) { 
  3.     const superClassPath = path.scope.getBinding(superClass.name).path; 
  4.     const allMethodNames = getAllClassMethodNames(superClassPath); 
  5.  
  6.     path.traverse({ 
  7.         ClassMethod(path) { 
  8.             if (path.node.override){ 
  9.                 const methodName = path.get('key').toString(); 
  10.                 const superClassName = superClassPath.get('id').toString(); 
  11.                 if (!allMethodNames.includes(methodName)) { 
  12.                     // 報錯                                     
  13.                 } 
  14.             } 
  15.         } 
  16.     }); 

報錯的部分使用 code frame 來創建友好的代碼打印格式,通過 Error.stackTraceLimit 設置為 0 去掉調用棧信息。

  1. const tmp = Error.stackTraceLimit; 
  2. Error.stackTraceLimit = 0; 
  3. let errorMessage = `this member cannot have an 'override' modifier because it is not declared in the base class '${superClassName}'`; 
  4. semanticErrors.push(path.get('key').buildCodeFrameError(errorMessage, Error)); 
  5. Error.stackTraceLimit = tmp; 

這樣,我們就完成了 override 的類型檢查,整體代碼如下:

  1. const { declare } = require('@babel/helper-plugin-utils'); 
  2.  
  3. function getAllClassMethodNames(classDeclarationNodePath) { 
  4.     const state = { 
  5.         allSuperMethodNames: [] 
  6.     } 
  7.     classDeclarationNodePath.traverse({ 
  8.         ClassMethod(path) { 
  9.             state.allSuperMethodNames.push(path.get('key').toString()) 
  10.         } 
  11.     }); 
  12.     return state.allSuperMethodNames; 
  13.  
  14. const overrideCheckerPlugin = declare((api, options, dirname) => { 
  15.     api.assertVersion(7); 
  16.  
  17.     return { 
  18.         pre(file) { 
  19.             file.set('errors', []); 
  20.         }, 
  21.         visitor: { 
  22.             ClassDeclaration(path, state) { 
  23.                 const semanticErrors = state.file.get('errors'); 
  24.  
  25.                 const superClass = path.node.superClass; 
  26.                 if (superClass) { 
  27.                     const superClassPath = path.scope.getBinding(superClass.name).path; 
  28.                     const allMethodNames = getAllClassMethodNames(superClassPath); 
  29.          
  30.                     path.traverse({ 
  31.                         ClassMethod(path) { 
  32.                             if (path.node.override){ 
  33.                                 const methodName = path.get('key').toString(); 
  34.                                 const superClassName = superClassPath.get('id').toString(); 
  35.                                 if (!allMethodNames.includes(methodName)) { 
  36.                                     const tmp = Error.stackTraceLimit; 
  37.                                     Error.stackTraceLimit = 0; 
  38.                                     let errorMessage = `this member cannot have an 'override' modifier because it is not declared in the base class '${superClassName}'`; 
  39.                                     semanticErrors.push(path.get('key').buildCodeFrameError(errorMessage, Error)); 
  40.                                     Error.stackTraceLimit = tmp;                                     
  41.                                 } 
  42.                             } 
  43.                         } 
  44.                     }); 
  45.                 } 
  46.                 state.file.set('errors', semanticErrors); 
  47.             } 
  48.         }, 
  49.         post(file) { 
  50.             console.log(file.get('errors')); 
  51.         } 
  52.     } 
  53. }); 
  54.  
  55. module.exports = overrideCheckerPlugin; 

github 鏈接

測試效果

我們用最開始的代碼來測試一下:

  1. class Animal { 
  2.     getName() { return ''; } 
  3. class Dog extends Animal { 
  4.     override bak() { 
  5.         return 'wang'
  6.     } 
  7.     override getName() { 
  8.         return 'wang'
  9.     } 

打印信息為:

正確的識別出了 bak 在父類不存在的錯誤。

至此,我們實現了 override 的類型檢查!

總結

類型檢查情況很多,所以需要一個系列文章去講,這一篇我們來實現 override 的類型檢查。

override 是 ts 4.3 加入的特性,帶有 override 修飾符的方法必須在父類中有對應的聲明,否則會報錯。

我們通過 babel 插件的方式實現了類型檢查,思路是從作用域取出父類的聲明,然后通過 path.traverse 拿到所有方法名,之后再取當前類的所有方法名,對于沒在父類中聲明并且帶有 override 修飾符的方法進行報錯。

本文是 【typescript 類型檢查原理】系列文章的第二篇,后續還會有更多 typescript 類型檢查的實現原理揭秘的文章。希望能夠幫助大家更好的掌握 typescript。

關于 babel 插件的知識,可以看我的 babel 小冊《babel 插件通關秘籍》,其中有詳細的講解。

本文源碼鏈接 https://github.com/QuarkGluonPlasma/babel-plugin-exercize/tree/master/exercize-type-checker/src

 

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2021-06-09 07:55:19

Typescript類型檢查

2022-04-11 08:42:09

TypeScript子類型定義

2022-05-04 09:02:41

TypeScript類型工具

2009-07-22 09:43:30

Scala類型

2022-04-10 19:26:07

TypeScript類型語法

2020-12-18 11:35:22

TypeScript語言Java

2022-09-14 15:24:57

typescript快排

2024-07-30 10:27:10

TypeScript配置TS

2012-07-02 10:43:49

JVMGroovyJava

2023-01-05 08:09:27

GroovyDSL?

2021-07-27 06:06:34

TypeScript語言運算符

2022-02-25 09:06:02

TypeScripnever工具

2013-07-09 14:41:58

C動態類型

2023-06-13 18:24:26

TypeScriptJSDoc開發

2022-08-08 09:00:42

TypeScript映射類型

2024-05-11 10:19:31

TypeScript類型接口

2021-08-18 07:56:05

Typescript類型本質

2022-02-09 08:11:50

架構

2020-06-04 07:51:30

MySQL死鎖加鎖

2021-05-08 07:57:17

ServletFilter設計模式
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久久久免费精品一区二区三区 | 国产精品夜间视频香蕉 | 91精品国产综合久久久密闭 | 视频一区二区在线观看 | 请别相信他免费喜剧电影在线观看 | 三级视频网站 | 我我色综合 | 国产精品欧美一区二区 | 中文字幕在线观看视频网站 | 国产激情在线 | 国产在线播| 日韩欧美一区二区三区免费观看 | 国产精品1区 | 日韩中文字幕在线免费 | 精品国产第一区二区三区 | 女人av | 国产精品一区二区三区四区 | 欧美一级大片免费看 | 国产精品欧美一区二区 | 欧美一级电影免费观看 | 中文字幕国产日韩 | 中文字幕一区二区三区在线观看 | 国产激情一区二区三区 | 日韩在线免费视频 | 国产午夜精品一区二区三区在线观看 | 亚洲国产一区二区三区在线观看 | 91高清免费观看 | 午夜影院视频在线观看 | 国产精品视频免费观看 | 一区免费 | 男人天堂国产 | 久国产 | 亚洲成人三区 | 日日干日日操 | 最新国产精品视频 | 九一视频在线观看 | 成人精品鲁一区一区二区 | 人妖无码| 亚卅毛片 | 国产女人与拘做视频免费 | 国产视频综合 |