2015-11-19 24 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()方法确保没有未知属性。

相关问题