Búsqueda de sitios web

typescript - Problemas al usar Partial<T> en un tipo genérico acotado


function f<T extends {id: string}>(id: T['id']): Partial<T> {
  return {id: id}; // ERROR: Type '{ id: T["id"]; }' is not assignable to type 'Partial<T>'
}

(Enlace a TypeScript Playground)

Estoy tratando de averiguar por qué el código anterior no está permitido. ¿Es fundamentalmente incorrecto? ¿O es debido a una limitación del sistema de tipos de TypeScript?

Respuesta #1

Esta es una característica faltante; el compilador no puede ver la asignación como válida y la rechaza por la misma razón que en ¿Por qué no puedo devolver un genérico 'T' para satisfacer un Partial?, aunque sería seguro permitirlo. Hubo un problema en microsoft/TypeScript#22229 solicitando que se abordara, pero se cerró como "funcionando según lo previsto". Por la discusión dentro de él, parece que es solo una característica faltante o una limitación de diseño.

Podrías, si quieres, usar una afirmación de tipo:

function fAssert<T extends {id: string}>(id: T['id']): Partial<T> {
  return {id: id} as Partial<T>; // assert
}

O podrías construir el valor de retorno en etapas (aunque este método es demasiado permisivo y permite algunas cosas no sólidas que probablemente tampoco se solucionarán pronto):

function fRoundabout<T extends {id: string}>(id: T['id']): Partial<T> {
  const ret: Partial<T> = {}; // allowed
  ret.id = id; // also works
  return ret;
}

No estoy 100% seguro de por qué quieres que el tipo de retorno sea Partial<T>, ya que dicho tipo puede o no tener valores en las claves de T, mientras que tu objeto retornado definitivamente tiene una propiedad id y nada más. Me parece más como Pick<T, "id"> que Partial<T>:

function fDifferentReturnType<T extends { id: string }>(id: T['id']): Pick<T, 'id'> {
  return { id: id }; // okay
}

Dado que el ejemplo es solo un ejemplo de juguete, es bastante posible que tu caso de uso real requiera Partial<T> y no {id: T['id']}. Pero si no es así, entonces podrías decidir evitar todo el problema de Partial por completo.

Está bien, con suerte una de esas sugerencias ayuda. ¡Buena suerte!

Enlace del parque

Respuesta #2

jcalz sugiere 3 opciones. ¿Cuál encaja?

Estoy de acuerdo con él en el hecho de que no está claro a partir de este ejemplo 'de juguete' si realmente hay necesidad de querer el tipo de retorno Partial<T>. Pick<T, 'id'> puede ser suficiente. En este caso, la inferencia funciona bien y puede ser una solución más simple:

function f<T extends {id: string}>(id: T['id']) {
  return { id }; // type: { id: T['id'] }
}