Короткий ответ
Работает, как и ожидалось, с TS> = 3.4
Чуть более длинный ответ
Asвы, возможно, уже заметили, TypeScript не очень хорош в выводе в целом.В своем примере кода вы предоставляете аннотацию для возвращаемого типа функции Either<Error, MyValidType>
, чтобы TS мог попытаться объединить все ветви в ожидаемый возвращаемый тип: без этой явной аннотации результаты были бы еще хуже.
Даже с ручной аннотацией типа TS до 3.4 будет «ленивым» и попытается разрешить все параметры универсального типа, объявленные функциями left
и right
(оба имеют L
и R
каквведите параметры) на месте, без «ожидания», чтобы получить лучшие знания, прежде чем принять этот выбор.Таким образом, было бы выведено Error
как L
для случая default
и { id: string, isValid: boolean }
как R
для случая true
.Проблема в том, что MyValidType
требует, чтобы isValid
было буквальным true
(более конкретным, чем boolean
), и поэтому в конечном итоге происходит сбой с
Type '{ id: string; isValid: boolean; }' is not assignable to type 'MyValidType'.
Types of property 'isValid' are incompatible.
Type 'boolean' is not assignable to type 'true'.
С TS> = 3.4
R
остается "нерешенным" до тех пор, пока в процессе, когда TS на самом деле знает ожидаемый (аннотированный) тип возвращаемого значения createMyValidType
и правильно видит литеральный объект как назначаемый объявленному типу возвращаемого значения.
Вы можете прочитать больше об этом улучшении в официальном журнале изменений на https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#higher-order-type-inference-from-generic-functions
Примечание 1
Эта проблема на самом деле не связана с fp-ts
, как с любымОбобщенная функция: аналогичная проблема возникает до 3.4:
declare function identity<T>(t: T): T;
function f(): { foo: 'foo' } {
return identity({ foo: 'foo' });
}
// Type '{ foo: string; }' is not assignable to type '{ foo: "foo"; }'.
// Types of property 'foo' are incompatible.
// Type 'string' is not assignable to type '"foo"'.
Примечание 2
Еще один способ взглянуть на этот пример состоит в том, что TS не выводит наиболее точную из возможныхлитеральные типы по умолчанию, за исключением некоторых конкретных случаев:
const foo = 'foo' // Type: "foo"
const fooObj = { foo: 'foo' } // Type: { foo: string }
Это "безопасное" значение по умолчанию с учетом изменчивости JS.Это поведение можно изменить с помощью «const
подтверждений»:
const fooObj = { foo: 'foo' } as const // Type: { readonly foo: "foo" }
Это еще одно дополнение в 3.4
(см. https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#const-assertions),, которое не является строго необходимым в вашем примере из-за возвратавведите аннотацию в createMyValidType
.