Me gustaría que mi función tome cualquier tipo de objeto, pero si el objeto tiene una propiedad 'id', asegúrese de que sea una cadena o un número.
Aquí está el ejemplo mínimo:
interface FnItem { id?: string | number; }; function fn<T extends FnItem>(item: T, callback: (item: T) => void) { console.log(item.id); callback(item) }; fn({ name: 'Michel' }, item => item.name); fn({ name: 'Michel', id: 12 }, item => item.name);me tira este error
Argument of type '{ name: string; }' is not assignable to parameter of type 'FnItem'. Object literal may only specify known properties, and 'name' does not exist in type 'FnItem' --- Property 'name' does not exist on type 'FnItemEl error te está diciendo todo lo que necesitas. el name no existe en su tipo FnItem . Puede solucionarlo agregando la propiedad o agregando una firma de índice si desea agregar claves arbitrarias como esta:
interface FnItem { id?: string | number; [key: string]: any; // or whatever types you accept };En cuanto al genérico, no puedo decir para qué lo necesita en este momento, ya que simplemente podría definir la función como
function fn(item: FnItem): voidSuponiendo que FnItem podría ser cualquier objeto con cualquier propiedad o cualquier objeto donde id sea number|string , preferiría seguir con esta solución:
type FnItem = Record<string, unknown> type IdValidation<Obj extends Record<string, unknown>> = Obj extends { id: infer Id } ? Id extends string | number ? Obj : Obj & { id: never } : Obj; function fn<T extends FnItem,>(item: IdValidation<T>, callback: (item: IdValidation<T>) => void) { console.log(item.id); callback(item) }; fn({ name: 'Michel' }, item => item.name); fn({ name: 'Michel', id: 12 }, item => item.id); fn({ name: 'Michel' }, item => item.ya); // error fn({ name: 'Michel', id: [] }, item => item.id); // id is highlighted as a wrong property Dado que el primer argumento puede ser cualquier objeto, deberíamos permitir pasar Record<string,unknown> que a su vez deshabilita nuestra restricción con respecto a que id sea number|string . Es por eso que he agregado el tipo de utilidad IdValidation . Simplemente verifica si la propiedad de id cumple con la condición o no. Si cumple, deje la id como está, de lo contrario, reemplace el tipo de id con never . El uso de never le permite resaltar solo la propiedad incorrecta, lo que facilita la lectura y la comprensión.
Si está interesado en las técnicas de validación de TS, puede consultar mis artículos aquí y aquí .
Si desea pasar un genérico, debe decirle a la función qué tipo concreto implementa su interfaz:
interface FnItem { id?: string | number; }; function fn<T extends FnItem>(item: T, callback: (item: T) => void) { console.log(item.id); callback(item); }; fn<myType>({ name: 'Michel', id: 12 }, (item:myType) => { console.log(item.name); }); fn<myType>({ name: 'Michel' }, (item:myType) => { console.log(item.name); }); class myType implements FnItem { name: string = ""; id?: number; }