У меня есть следующий код, который я использую для отслеживания статусов асинхронных запросов. В качестве дискриминатора используется _type
, а также status
.
В следующем коде я определяю два типа AsyncStatus: LoginAsyncStatus
и SearchAsyncStatus
. Они различаются _type
и success
value
.
Проблема в том, что TypeScript, похоже, неправильно сужает тип размеченного объединения.
export type AsyncStatus<BrandT extends string, T = undefined> =
| { id: string; _type: BrandT; error?: never; state: "loading"; value?: never; }
| { id: string; _type: BrandT; error: Error; state: "error"; value?: never }
| { id: string; _type: BrandT; error?: never; state: "success"; value: T };
export type ExtractAsyncStatusByType<
TName extends ApiAsyncStatus["_type"],
TType
> = TType extends AsyncStatus<TName, any> ? TType : never;
export type LoginAsyncStatus = AsyncStatus<"LOGIN", { refreshToken: string }>;
export type SearchAsyncStatus = AsyncStatus<"SEARCH", string[]>;
export type ApiAsyncStatus = LoginAsyncStatus | SearchAsyncStatus;
export type Registry = Partial<Record<ApiAsyncStatus["id"], ApiAsyncStatus>>;
export const getApiAsyncStatus = <T extends ApiAsyncStatus["_type"]>(
registry: Registry,
id: string,
type: T,
): ExtractAsyncStatusByType<T, ApiAsyncStatus> | undefined => {
let status = registry[id];
if (status !== undefined && status._type !== type) {
/**
* Property 'value' is missing in type
* '{ _type: T; error: Error; id: string; state: "error"; }'
* but required in type
* '{ id: string; _type: "SEARCH"; error?: undefined; state: "success"; value: string[]; }'
* .ts(2322)
*/
status = {
_type: type,
error: new Error(`Expected _type ${type}, but received ${status._type}`),
id,
state: "error",
}; // err
}
return status as ExtractAsyncStatusByType<T, ApiAsyncStatus> | undefined;
};
Я обновил исходный вопрос, в котором вопрос касался возврата соответствующего типа в случае, когда я не пытался динамически создавать статус.
getApiAsyncStatus()
типT
является неразрешенным универсальным параметром, и компилятор не выполняет много работы, пытаясь проверить, можно ли присвоить значение условному типу, зависящему от такого неразрешенного универсального параметра. Лучше всего здесь просто использовать утверждение типа (return status as Extract<ApiAsyncStatus, {_type: T}>
или подобное) или что-то подобное (например, использовать подпись перегрузки). Преимущество этого условного типа для вызывающих, а не для разработчиков. - person jcalz   schedule 02.06.2019Registry
используетPartial
иRecord
, но, похоже, здесь не проблема) - person jcalz   schedule 02.06.2019