Я не очень разбираюсь в том, почему это работает в TypeScript 2.6, но причина, по которой это не удается сейчас, заключается в том, что компилятор защищает вас от чего-то маловероятного, и в любом случае не достаточно умен, чтобы понять, чтотип handlers[a.kind]
соотносится с a
.
Рассмотрим следующий допустимый, но неприятный код:
const resolved = resolver<"a" | "b">({ someString: "whoops", kind: "b" });
Поскольку Key extends keyof HashType
, Key
может быть равно до keyof HashType
.И обратите внимание, что данный аргумент является Command<keyof HashType>
, даже если это не Command<"a">
или Command<"b">
.Компилятор не может гарантировать, что handlers[a.kind]
будет применяться к a
.
Может ли это быть проблемой при реальном использовании кода?Возможно нет.Если нет, вы можете утверждать, что знаете больше, чем компилятор, и используете утверждение типа :
function resolver<Key extends keyof HashType>(a: Command<Key>): HashType[Key]['out'] {
const handler = handlers[a.kind] as (arg: Command<Key>) => HashType[Key]['out'];
return handler(a);
}
Теперь код успешно компилируется.Если вы беспокоитесь о том, что кто-то передаст слишком широкий аргумент в код, есть способы обойти это.Но это, вероятно, не стоит того.
Надеюсь, это поможет!По аналогичной проблеме смотрите этот вопрос .