2015-11-19 25 views
19

予加載在運行時JSON配置文件,並使用接口來定義它的預期結構的接口:檢查是否一個對象實現在與打字稿運行時

interface EngineConfig { 
    pathplanner?: PathPlannerConfig; 
    debug?: DebugConfig; 
    ... 
} 

interface PathPlannerConfig { 
    nbMaxIter?: number; 
    nbIterPerChunk?: number; 
    heuristic?: string; 
} 

interface DebugConfig { 
    logLevel?: number; 
} 

... 

這使得方便的,因爲訪問的各種屬性我可以使用自動完成等。

問題:有沒有辦法使用這個聲明來檢查我加載的文件的正確性?即我沒有意想不到的屬性?

+1

僅供參考:[檢測TypeScript動態中的對象實現接口](http://stackoverflow.com/questions/16013667/detect-whether-object-implement-interface-in-typescript-dynamicaly) –

+0

可能的重複[使用Typescript檢查接口類型](https://stackoverflow.com/questions/14425568/interface-type-check-with-typescript) –

回答

1

我不知道你的配置文件是怎麼樣的,但最明顯的是json文件,儘管我會用json模式來驗證文件是否符合模式。

這裏的JSON模式v4的文檔:http://json-schema.org/documentation.html

和例子,你怎麼能測試一個:https://github.com/fge/json-schema-validator

當然,你必須基於接口寫你的架構,但你不能直接使用它們。

+0

是的,它是JSON,但我的目標是在運行時使用已有的接口(或任何其他解決方案,我不需要兩次寫配置結構) – MasterScrat

+1

您可以在運行時驗證該文件(使用ajax請求加載它並檢查它是否有效)。但讓我解釋一件事:接口是您的JavaScript對象的模式,它只用於編譯時間。但是它缺少太多的信息用作驗證器。例如,如何在界面中編寫一些數組應至少包含三個枚舉值?您必須編寫架構才能讓對象具有更大的靈活性。有一些在線生成器可以根據你的json文件構建模式,比如http://jsonschema.net/ –

5

是指出。您可以在運行時通過使用前幾次發佈的TypeScript編譯器的增強版進行此檢查。你可以做類似如下:

export interface Person { 
    name: string; 
    surname: string; 
    age: number; 
} 

let personOk = { name: "John", surname: "Doe", age: 36 }; 
let personNotOk = { name: 22, age: "x" }; 

// YES. Now you CAN use an interface as a type reference object. 
console.log("isValid(personOk): " + isValid(personOk, Person) + "\n"); 
console.log("isValid(personNotOk): " + isValid(personNotOk, Person) + "\n"); 

,這是輸出:

isValid(personOk): true 

Field name should be string but it is number 
isValid(personNotOk): false 

請注意:isValid功能工作遞歸,所以你可以用它來驗證嵌套的對象,太。你可以找到完整的工作示例here

+0

整潔,任何希望得到TypeScript中內置的東西。我認爲這是AtScript和Angular 2所需要的。 – jpierson

+0

官方的TypeScript編譯器不會涵蓋(也可能永遠不會)反射,因爲它被稱爲「超出範圍」。對我而言,這是一項爲期10天的開發工作,我不是核心團隊:在生效之前,我必須學習很多東西。 TypeScript團隊的成員之一可以在一週或更短的時間內完成此任務。簡而言之:在TypeScript中反射實現沒有任何不可能的或*太難*。 – pcan

5

我懷疑TypeScript(明智地)遵守Curly定律,而Typescript是一個轉譯器,而不是一個對象驗證器。也就是說,我還認爲打字稿界面會導致糟糕的對象驗證,因爲界面有一個(奇妙)有限的詞彙表,並且無法驗證其他程序員可能用來區分對象的形狀,例如數組長度,屬性數量,圖案特性等

當消耗來自非打字稿代碼對象,我使用了JSONSchema驗證包,如AJV,用於運行時間驗證,和一個.d.ts文件發生器(如DTSgeneratorDTS-generator)從我的JSONshcema中編譯TypeScript類型定義。

主要需要注意的是,由於JSONschemata能夠描述不能被打字稿進行區分的形狀(如patternProperties),它不是從JSON架構.t.ds一個到一個翻譯,你可能有做一些手工編輯生成的.d。ts文件時使用這種JSON模式。這就是說,因爲其他程序員可能會使用像數組長度這樣的屬性來推斷對象類型,所以我習慣區分可能被TypeScript編譯器使用枚舉來混淆的類型,以防止轉譯器接受一種類型的使用在地方,其他像這樣的:

[MyTypes.yaml] 

definitions: 
    type-A: 
     type: object 
     properties: 
      type: 
       enum: 
       - A 
      foo: 
       type: array 
       item: string 
       maxLength: 2 
    type-B: 
     type: object 
     properties: 
      type: 
       enum: 
       - B 
      foo: 
       type: array 
       item: string 
       minLength: 3 
     items: number 

生成一個.d.ts文件像這樣:

[MyTypes.d.ts] 

interface typeA{ 
    type: "A"; 
    foo: string[]; 
} 

interface typeB{ 
    type: "B"; 
    foo: string[]; 
} 
4

有「是」的方式,但你必須實現它自己。它被稱爲「用戶定義類型衛士」,它看起來像這樣:

interface Test { 
    prop: number; 
} 

function isTest(arg: any): arg is Test { 
    return arg && arg.prop && typeof(arg.prop) == 'number'; 
} 

當然,isTest功能的實際執行是完全取決於你,但好的部分是,它是一個真正的功能,意味着它是可測試的。

現在在運行時,您將使用isTest()來驗證對象是否遵守接口。在編譯時打字稿拿起在保護和對待如預期後續使用,即:

let a:any = { prop: 5 }; 

a.x; //ok because here a is of type any 

if (isTest(a)) { 
    a.x; //error because here a is of type Test 
} 

更深入的解釋在這裏:https://basarat.gitbooks.io/typescript/content/docs/types/typeGuard.html

+0

有趣。看起來像是可以自動生成的東西。 – MasterScrat

+0

是的,它可以是自動的,而且對於常見情況的確很容易。然而,用戶定義的後衛可以做特定的事情,比如檢查數組的長度或者根據正則表達式驗證字符串。每個字段的註釋會有所幫助,但是我認爲它應該是一個類而不是一個接口。 – Mtz

+0

這應該是被接受的答案。 – RichardForrester

0

這是一個好方法。您可以使用typescript-json-schema將TypeScript接口轉換爲JSON模式。

typescript-json-schema --required --noExtraProps \ 
    -o YOUR_SCHEMA.json YOUR_CODE.ts YOUR_INTERFACE_NAME 

然後在運行時使用JSON模式驗證如ajv,例如驗證數據

const fs = require('fs'); 
const Ajv = require('ajv'); 

// Load schema 
const schema = JSON.parse(fs.readFileSync('YOUR_SCHEMA.json', {encoding:"utf8"})); 
const ajv = new Ajv(); 
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json')); 
var validator = ajv.compile(schema); 

if (!validator({"hello": "world"})) { 
    console.log(validator.errors); 
} 
0

這裏是另一種選擇,專門爲此:

ts-interface-builder是你在編譯的時候你的打字稿文件(例如foo.ts)運行建設運行的描述符(例如foo-ti.ts)的工具。

ts-interface-checker使用這些在運行時驗證對象。例如。

import {createCheckers} from 'ts-interface-checker'; 
import fooDesc from 'foo-ti.ts'; 
const checkers = createCheckers(fooDesc); 

checkers.EngineConfig.check(someObject); // Succeeds or throws an informative error 
checkers.PathPlannerConfig.check(someObject); 

您可以使用strictCheck()方法確保沒有未知屬性。

相關問題