0
4

1 回答 1

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


链接到代码

于 2019-09-01T17:45:59.217 回答