Typescript自定义工具,转译器,扩展
我想在tsc
之前更改/检查.ts
文件,它将开始其转译过程,类似于Roslyn为C#提供的。
这对静态类型检查很有用。 例如,正确和短的Immutable Record
实现需要在编译时进行代码更改/静态检查,因为它可以使用Flow完成:
@Record(Person)
interface IPerson {
givenName: string;
familyName: string;
}
然后自定义tsc transpiler可以修改代码来:
interface IPersonParams {
givenName?: string;
familyName?: string;
}
@Record()
class Person {
private readonly __givenName;
private readonly __familyName;
constructor(init) {
this.__givenName = init.givenName;
this.__familyName = init.familyName;
}
get givenName() {
return this.__givenName;
}
get familyName() {
return this.__familyName;
}
update(update: IPersonParams) {
// ignore the bug when undefined param is passed
return new Person({
givenName: update.givenName || this.__givenName,
familyName: update.familyName || this.__familyName
});
}
}
立即看到自定义编译错误会很好,因为现在使用Visual Studio和Visual Studio Code完成特殊的tsc watch
,而不是作为webpack绑定或自定义gulp任务的一部分。 有一个用于Typescript的API,但是如何使它与VS/VS Code/Atom
tsc
无缝协作?
用示例更新
目标只是写
@Record(Person)
interface IPerson {
givenName: string;
familyName: string;
}
如前所示, Person
类将根据接口IPerson
自动生成。
可以实例化对象:
let instance = new Person({givenName: "Emma", familyName: "Watson"});
任何不正确的属性都会引发编译错误:
let instance = new Person({nonExistedProperty: "Emma"}); //error
错误:属性'nonExistedProperty'在类Person构造函数中不存在;
错误:属性'givenName'在类Person构造函数中是必需的;
错误:属性'familyName'在类Person构造函数中是必需的;
现有对象应该能够部分更新
let instance = new Person({givenName: "Emma", familyName: "Watson"});
instance.Update({givenName: "Luise"});
instance.givenName === "Luise"; //TRUE;
instance.familyName === "Watson"; //TRUE;
所有属性都是只读的
let instance = new Person({givenName: "Emma", familyName: "Watson"});
instance.givenName = "John"; //error
错误:属性'givenName'是只读的;
Equals
方法是自动生成的。 它可以基于散列或其他任何东西,但应该快速工作并提供深入检查。
let instance1 = new Person({givenName: "Emma", familyName: "Watson"});
let instance2 = new Person({givenName: "Emma", familyName: "Watson"});
instance1.Equals(instance2); //TRUE
它也可能有一个控制创建实例的位置,如果内部字典中存在具有相同参数的记录,则它只是返回对该对象的引用:
let instance1 = new Person({givenName: "Emma", familyName: "Watson"});
let instance2 = new Person({givenName: "Emma", familyName: "Watson"});
instance1 == instance2; //TRUE
instance1 === instance2; //TRUE
也许不用编写自己的打字稿(预处理器),你可以通过使用TypeScript装饰器来实现你的目标。
这个例子来自https://www.typescriptlang.org/docs/handbook/decorators.html:
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
这是我迄今发现的。 目前没有简单的方法(2017年)。
一种解决方案是创建一个使用Typescript API的自定义插件。 它还将在自己的沙箱中第二次运行服务,并与VS Code
, Atom
或VS
TS服务一起运行。 除此之外,每个IDE都需要将自己的插件创建为核心插件/服务之上的包装。
通过这种方式,有些人已经制作了短信,例如vscode-ng-language-service和ng2linter。
Microsoft拥有用于TypeScript扩展性的#6508票据,这将使请求的功能成为可能并且易于实现。
对于那些使用C#
和F#
编程的人来说,使用Roslyn
的可能性可能会更好,而不是等待TypeScript扩展。 用C#编写的代码可以转换为TypeScript或JavaScript。 它还为各种检查和自定义修改打开了广泛的可能性。 当然,如果在.NET
和TypeScript/Javascript
有相同的逻辑,它更接近DRY原则。 Bridge.NET不使用Roslyn,但有很好的实现。 用于.NET 4和Roslyn的Rosetta项目似乎是一个好的开始。
没有任何编译器的魔力,这都是可能的。
外部库
declare function someGenericEqualsFn(a, b): boolean;
declare function makeCached<TResult, TFunc extends (...args) => TResult>(funcToCache: TFunc): TFunc;
declare function merge<T>(objectToUpdate: T, objectToMerge: Partial<T>);
我们的库:
interface DataRecord<TRecord> {
equals<TRecord>(other: TRecord): boolean;
update(update: Partial<TRecord>);
}
function createDataRecord<TRecord>(data: TRecord): Readonly<TRecord> & DataRecord<TRecord> {
const result: TRecord & DataRecord<TRecord> = <any>{};
Object.keys(data).forEach(() => {
});
result.equals = function (other: TRecord) {
return someGenericEqualsFn(result, other);
};
result.update = function (partial: Partial<TRecord>) {
merge(result, partial);
};
return result;
}
我们的测试:
interface IPerson {
givenName: string;
familyName: string;
}
let instance = createDataRecord<IPerson>({givenName: "Emma", familyName: "Watson"});
instance = createDataRecord<IPerson>({nonExistedProperty: "Emma"}); // compiler error
instance.givenName = "John"; // compiler error
instance.update({givenName: "Emma"}); // works!
instance.update({nonExistedProperty: "x"}); // compiler error
const createDataRecordOrGetCached = makeCached(createDataRecord);
let instance1 = createDataRecordOrGetCached({givenName: "Emma", familyName: "Watson"});
let instance2 = createDataRecordOrGetCached({givenName: "Emma", familyName: "Watson"});
instance1 == instance2; //TRUE
instance1 === instance2; //TRUE
链接地址: http://www.djcxy.com/p/38153.html