typescript - Hacer opcionales las claves que tengan un carácter específico en su nombre
Di que tengo un objeto como:
const obj = {
a: 1,
"b?": 2,
"c?": 3
}
Su tipo actualmente es:
type Obj = {
a: number;
"b?": number;
"c?": number;
}
¿Hay alguna manera de crear un tipo que acepte obj y convierta su tipo a:
type Obj = {
a: number;
b?: number;
c?: number;
}
Esencialmente haciendo que b y c sean opcionales.
Respuesta #1
Puedes hacerlo utilizando tipos de literales de plantilla e inferencia. Dividiéndolo en partes (pero las combinaremos al final):
Primero queremos obtener las propiedades requeridas:
type MapRequiredKeys<T> = { [Key in keyof T as Key extends `${string}?` ? never : Key]: T[Key]; };Ahí, si
Keycoincide con el patrón$ {string}?, lo omitimos usandonevercomo la clave; de lo contrario, usamos la clave. Usando eso entypeof objnos da{ a: number; }.Luego queremos los opcionales, y solo queremos la parte base de la clave, no el
?. Ahí es donde entrainfer:type MapOptionalKeys<T> = { [Key in keyof T as Key extends `${infer BaseKey}?` ? BaseKey : never]?: T[Key]; };Comparamos
Keycon$ {infer BaseKey}?y luego usamosBaseKeysi coincide (dejando de lado la propiedad por completo si no coincide). Usamos?en ella para hacer que la propiedad sea opcional.Combinándolos:
type MapKeys<T> = MapRequiredKeys<T> & MapOptionalKeys<T>; type ObjType = MapKeys<typeof obj>;Ejemplo de patio de juegos
Pero podemos combinarlos en un solo tipo, lo que hace que las sugerencias que TypeScript nos da sean más claras:
type MapKeys<T> = {
[Key in keyof T as Key extends `${string}?` ? never : Key]: T[Key];
} & {
[Key in keyof T as Key extends `${infer BaseKey}?` ? BaseKey : never]?: T[Key];
};
type ObjType = MapKeys<typeof obj>;
Ejemplo de patio de juegos
Si pasas el cursor sobre ObjType allí, ves type ObjType={ a: number; } & { b?: number | undefined, c?: number | undefined; } en lugar de ver las "llamadas" a MapRequiredKeys y MapOptionalKeys.
