1 回答
关于 TypeScript 中的命名约定的注意事项:通用类型参数名称通常只有一两个大写字符,尽管这样缺乏表达力。并且类型别名和接口几乎总是以首字母大写命名,而非构造函数值几乎总是以首字母小写命名。我将在这里遵循这些约定。
我认为最好的方法是创建从鉴别RuntimeDiscriminator
器到鉴别Semantic
类型的映射,并使您的Checkpoint
类在鉴别器本身中具有通用性。就像是:
interface SemanticMap {
Script: Script;
Statement: Statement;
}
type RuntimeDiscriminator = keyof SemanticMap;
SemanticMap
请注意,您的代码中不必有接口的单个实例;它只是为了帮助类型系统理解字符串文字名称和类型之间的关系(并且接口非常适合将字符串文字名称映射到类型)
class Checkpoint<K extends RuntimeDiscriminator> {
type: K;
constructor(blah: any, type: K) {
this.type = type;
}
producesScript(): this is Checkpoint<"Script"> {
return this.type === "Script";
}
producesStatement(): this is Checkpoint<"Statement"> {
return this.type === "Statement";
}
然后您可以将您的Semantic
类型称为查找类型 SemanticMap[K]
,如方法的签名中continue()
所示:
continue<T>(callback: (val: SemanticMap[K]) => T): T {
return callback(getSemanticInstance(this.type)); // or something
}
}
(您可能会发现自己需要在 的实现中使用类型断言等continue()
,因为编译器通常不喜欢将具体值分配给泛型类型;它无法验证这些值是否安全,也不会真正尝试,请参阅microsoft/TypeScript#24085。即使在您的代码中也是如此;这并不是使用SemanticMap[K]
而不是. 的具体限制Semantic
。)
让我们验证它的行为是否符合您的要求:
function scriptAcceptor(s: Script): string {
return "yummy script";
}
function statementAcceptor(s: Statement): string {
return "mmmm statement";
}
const scriptCheckpoint = new Checkpoint(12345, "Script"); // Checkpoint<"Script">
const scrVal = scriptCheckpoint.continue(scriptAcceptor); // string
const statementCheckpoint = new Checkpoint(67890, "Statement"); // Checkpoint<"Statement">
const staVal = statementCheckpoint.continue(statementAcceptor); // string
const oops = scriptCheckpoint.continue(statementAcceptor); // error!
// ~~~~~~~~~~~~~~~~~
// Argument of type '(s: Statement) => string' is not assignable
// to parameter of type '(val: Script) => string'.
这对我来说是正确的。
顺便说一句,我认为如果您决定以continue()
调用这些类型保护并打开结果的方式来实现该方法,您可能会考虑创建Checkpoint<K>
一个抽象超类并拥有每个实现自己的方法的具体ScriptCheckpoint extends Checkpoint<"Script">
和子类。你会用. 这减轻了必须像两个不同的事物一样行事的负担。不过我不知道你的用例,所以我不会在这个方向上走得更远;这只是需要考虑的事情。StatementCheckpoint extends Checkpoint<"Statement">
continue()
new Checkpoint(blah, "Script")
new ScriptCheckpoint(blah)
Checkpoint