typescript - Hur kan jag filtrera en union baserat på närvaron eller frånvaron av en egenskap
Jag har en typ IResponse för ett API-svar sammanfogat med ELLER som varierar beroende på en URL-sökparameter.
här är hur jag avser att använda det
const data1 = await request<E<"aaa">>('/api/data/1?type=aaa');
const data2 = await request<E<"bbb">>('/api/data/1?type=bbb');
function request<T>(
url: string
): Promise<T> {
return fetch(url, config)
.then((response) => response.json())
.then((data) => data as T);
}
//index.ts
import {
paths,
} from "./autoGeneratedTypes";
type IResponse =
paths["/api/data/{id}"]["get"]["responses"]["200"]["content"]["application/json"];
export type E<T extends "aaa" | "bbb"> = T extends "aaa"
? Omit<IResponse, "ca">
: Pick<IResponse, "ca">;
export type F = E<"aaa">["bb"];
Jag får ett fel vid Pick<IResponse, "ca"> som säger Typen 'string' uppfyller inte begränsningen 'never'
Jag vill inte direkt referera till scheman C eller B eftersom deras schemanamn kan ändras, så jag behöver en typ som kommer att extrahera rätt typ för API-svaret från IResponse.
//autoGeneratedTypes.ts
/**
* This file was auto-generated by openapi-typescript.
* Do not make direct changes to the file.
*/
export interface paths {
"/api/data/{id}": {
/** @description get the data */
get: {
responses: {
/** @description Retrieved the data successfully */
200: {
content: {
"application/json": components["schemas"]["D"];
};
};
};
};
};
}
export interface components {
schemas: {
D: components["schemas"]["C"] | components["schemas"]["B"];
C: {
ca: components["schemas"]["B"][];
};
B: {
ba: string;
bb: components["schemas"]["A"][];
};
A: {
aa: string;
ab: string | null;
};
};
}
https://www.typescriptlang.org/play?ts=4.9.5#code/C4TwDgpgBAglC8UDeBYAUFKBDLAuKAzsAE4CWAdgOYDc6mWARvkWVVAD5TkCuANr7TQBfQelCQoAIQTI6UBnkIkKNOQyawA2gF1BI9GPDQAwjNQYoAY0WS9otOOgARGac62DaCAA8wAe2JgKEcoAFEAHgAVKB9gCHIAEwIoACIcLBSOVPUGFIA+GWjY+KTU9JS5AH4oAHkAW1JgcKcAGlTrfLl8AAVSSwBrZraUjrz7H39A4KMoAFksMDAVAgB1RoALY25iYnjLEBkItJx8zRT1FN10IA
Svar #1
Du kan använda Extract<T, U> och Exclude<T, U> hjälptyper för att filtrera unionstyper. Dessa typer tar en unionstyp T och behåller (för Extract) eller avvisar (för Exclude) alla medlemmar av T som kan tilldelas till U.
I ditt fall ser det ut som att du vill:
type E<T extends "aaa" | "bbb"> =
T extends "aaa" ? Exclude<IResponse, { ca: any }> : Extract<IResponse, { ca: any }>
som producerar
export type F = E<"aaa">["bb"]; // okay
/* type F = {
aa: string;
ab: string | null;
}[] */
som önskat.
Din version fungerade inte eftersom Pick<T, K> och Omit<T, K> hjälptyper filtrerar egenskaperna av typen T, och fungerar inte bra när T är en union eftersom de inte distribueras över unioner i T.
Playground-länk till kod
