¿Puedo obtener una lista de nombres de campo de una interfaz cuyos tipos son de un tipo dado?
Por ejemplo, si tengo esta interfaz
interface Measurement {
date: Date
width: number
height: number
depth: number
comment: string
}
¿Hay alguna manera de conseguir lo siguiente?
const numericFields = ['width', 'height', 'depth']
const dateFields = ['date']
const stringFields = ['comment']
Alternativamente, ¿hay una manera de crear una función como la siguiente?
// not sure about the signature, but hopefully you get the idea
function getInterfaceFieldsWithType: keyof I[]
const numericFields = getInterfaceFieldsWithType()
Pregunta hecha hace 3 años, 4 meses, 27 días - Por bughunterx
3 Respuestas:
-
Primer enfoque muy ingenuo:
interface Measurement { date: Date width: number height: number depth: number comment: string } type GetByType
= { [P in keyof T]: T[P] extends V ? P : never }[keyof T] /** * Just an alias to reduce repetitive code */ type Get = Array > const numericFields: Get = ['width', 'height', 'depth'] const dateFields: Get = ['date'] const stringFields: Get = ['comment'] Retrocede:
const numericFields: Get
= ['width', 'height', 'depth', 'depth', 'width'] // valid from TS perpective Si desea prohibir las dublicciones por TS, puede intentar esta respuesta
Si quieres estar 100% seguro de que no hay dublications en tiempo de ejecución, la mejor manera es usar
Set's
:const array = [...new Set([1, 2, 3, 4, 4])] // [1, 2, 3, 4]
Segundo enfoque
interface Measurement { date: Date width: number height: number depth: number comment: string } // filter all properies type GetByType
= { [P in keyof T]: T[P] extends V ? P : never }[keyof T] /** * Just an alias to reduce repetitive code */ type Result = GetByType type Values = T[keyof T] /** * because our second argument is stringified type name, * we need some sort of vice-versa mapping */ type LiteralToType = T extends 'string' ? string : T extends 'number' ? number : T extends 'Date' ? Date : never; type TypeToLiteral = T extends string ? 'string' : T extends number ? 'number' : T extends Date ? 'Date' : never; const getInterfaceFieldsWithType = < Obj extends Record , Type extends TypeToLiteral > // I need a guarantee that we have at least one property with expected type >(obj: Obj, expectedType: Type): GetByType >[] => { const keys = (Object.keys(obj) as Array ) /** * Here, filter is a typescript guard * It says: if I return true, then you can sleep well, this key is what you need */ return keys.filter((elem): elem is GetByType > => typeof obj[elem] === expectedType) } /** * Tests */ const result = getInterfaceFieldsWithType({ date: '01-01-2021', width: 24, height: 42, numberdepth: 2, comment: 'hello' }, 'number') // ok ("width" | "height" | "numberdepth")[] const result2 = getInterfaceFieldsWithType({ date: new Date(), width: 24, height: 42, numberdepth: 2, comment: 'hello' }, 'Date') // ok "date"[] const result3 = getInterfaceFieldsWithType({ date: new Date(), width: 24, height: 42, numberdepth: 2, comment: 'hello' }, 'string') // ok "comment"[] const result4 = getInterfaceFieldsWithType({ date: new Date(), width: 24, height: 42, numberdepth: 2, comment: 'hello' }, 'Promise') // error Si todavía quieres permitir tipos de propiedades no existentes, como
Promise
, puedes añadir el siguiente Sobrecarga a su funcióntype EmptyArray = readonly string[]; interface Overloading { < Obj extends Record
, Type extends TypeToLiteral > //I need a guarantee that we have at least one property with expected type >(obj: Obj, expectedType: Type): ReadonlyArray >> < Obj extends Record , Type extends string // I need a guarantee that we have at least one property with expected type >(obj: Obj, expectedType: Type): EmptyArray } Respondida el Dec 18, 2020 a las 11:51 - por syntaxsensei8acf
Votos positivos: 0 | Votos negativos: 0 -
Para lograr obtener una lista de nombres de campo de una interfaz cuyos tipos son de un tipo dado, puedes utilizar TypeScript y definir una función genérica que funcione de la siguiente manera:
typescript interface Measurement { date: Date width: number height: number depth: number comment: string } type FieldsOfType
= { [K in keyof T]: T[K] extends U ? K : never; }[keyof T][]; function getInterfaceFieldsWithType (obj: T, type: U): FieldsOfType { const keys = Object.keys(obj) as (keyof T)[]; return keys.filter(key => obj[key] instanceof type) as FieldsOfType ; } const measurement: Measurement = { date: new Date(), width: 10, height: 5, depth: 3, comment: "Example" }; const numericFields = getInterfaceFieldsWithType(measurement, Number); const dateFields = getInterfaceFieldsWithType(measurement, Date); const stringFields = getInterfaceFieldsWithType(measurement, String); console.log(numericFields); // Output: ['width', 'height', 'depth'] console.log(dateFields); // Output: ['date'] console.log(stringFields); // Output: ['comment'] En este código, la función
getInterfaceFieldsWithType
toma un objeto de tipoT
y un tipoU
como argumentos, y devuelve una lista de nombres de campo deT
cuyos tipos son deU
. La función utiliza mapeo condicional para filtrar los campos cuyo tipo coincida conU
. Luego puedes llamar a esta función con el objetomeasurement
y el tipo deseado para obtener las listas de campos correspondientes.Respondida el Dec 19, 2020 a las 11:54 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
Opción 1: Usar tipos de TypeScript
Puedes aprovechar los tipos de TypeScript para lograr esto de la siguiente manera:
typescript interface Measurement { date: Date; width: number; height: number; depth: number; comment: string; } const numericFields = Object.keys(Measurement).filter(key => typeof Measurement[key] === 'number'); const dateFields = Object.keys(Measurement).filter(key => Measurement[key] instanceof Date); const stringFields = Object.keys(Measurement).filter(key => typeof Measurement[key] === 'string');
Opción 2: Usar una función genérica
También puedes crear una función genérica que tome una interfaz y un tipo como argumentos y devuelva una lista de nombres de campo que coincidan con el tipo:
typescript function getInterfaceFieldsWithType(inter: I): (keyof I)[] { return Object.keys(inter).filter(key => typeof inter[key] === T); } const measurement = { date: new Date(), width: 10, height: 15, depth: 20, comment: 'This is a measurement', }; const numericFields = getInterfaceFieldsWithType
(measurement); Ejemplo de uso:
typescript // Usa la función getInterfaceFieldsWithType const numericFields = getInterfaceFieldsWithType
(); // Usa los tipos de TypeScript const stringFields = Object.keys(Measurement).filter(key => typeof Measurement[key] === 'string'); Respondida el Dec 19, 2020 a las 12:00 - por Gemini
Votos positivos: 0 | Votos negativos: 0