microsoft / microsoft/TypeScript

JSX types should automatically pick setter types instead of getter types.

Abierto
#61,341 1 comentario 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Awaiting More Feedback Suggestion
Lenguaje dominante
Go
Estrellas
111k
Forks
14.3k
Merge medio
2 d 4 h
PR fusionados (30 d)
132

Descripción

🔍 Search Terms

"typescript github jsx setter type"

Related:

(however that issue is for mapped types in general, while this one is for fixing how TypeScript's internal mechanism reads types passed into JSX (UppercaseComponents) or JSX.IntrinsicElements)

✅ Viability Checklist
⭐ Suggestion

When using a class definition for a JSX type, the JSX prop types will type check against the getter, not the setter of a class property.

📃 Motivating Example

Although JSX can require or not require certain values, JSX is effectively a language feature for passing or setting values.

They should be treated mode like optional parameters ? is specified, and should otherwise look at setter types to achieve the semantics they truly align with.

Here's an example:

class MyClass {
  get foo(): number {...}
  set foo(value: string | number) {...}
}

function Component() {
  // This is valid:
  return <MyClass foo={"123"} /> // TYPE ERROR ("string not assignable to number")
}

We get a type error, but "123" is a valid value because the foo setter accepts string values based on its type definition.

But this is the crux: we're not getting the class value, we're setting it, for all intents and purposes. It doesn't matter if under the hood we're actually creating a vdom object, as that is merely an implementation detail, while the language itself is really determing other use cases:

  • we're passing values to a function
  • we're setting values on an object
  • we're assigning values onto an object

As an example, this is especially true with Custom Elements, in situations like this,

return <some-custom-element someProp={123} />

where we are setting a property on the DOM element instance.

The problem is that TypeScript is type checking JSX props based on the getter type of a property, but in fact they are effectively setters that are meant to pass values to their destination, the user is not getting a value from the JSX.

An example Custom Element definition:

class SomeEl extends HTMLElement {
  #someProp = 123 // type is 'number'

  // returns 'number'
  get someProp() { return this.#someProp }

  // accepts 'string | number'
  set someProp(val: string | number) { this.#someProp = Number(val) }
}

customElements.define('some-custom-element', SomeEl)

To represent this, TypeScript needs to effectively treat JSX props as similar to function parameters instead of as an object type, allowing some "parameters" to be optional, and preferring setter types when those exist.

It is possible someone will assign SomeEl into JSX.IntrinsicElements for JSX type checking,

declare module 'some-jsx-framework' {
  namespace JSX {
    interface IntrinsicElements {
      'some-custom-element': SomeEl
    }
  }
}

so the system would need to take in the object/class type, and map that to its internal handling of JSX which would be more like parameter, having preferred any setter types when they exist.

This playground example show a type error for a valid value.

💻 Use Cases
  1. This will improve JSX type definitions.
  2. Current approaches are limited to getter types, and JSX cannot fully represent desired types.
  3. Workarounds include declaring fake properties with conventional syntax such as __jsx__foo: string | number from which a mapped type can map to a JSX type definition. Example:
    const MyClass = class MyClass {
      get foo(): number {...}
      set foo(value: string | number) {...}
      /** End users: do not use this, this is for JSX types only. */
      __jsx__foo: string | number
    }
    
    // This is a special mapped type that maps `__jsx__*` properties for JSX types.
    type MyClass = MySpecialMappedType<typeof MyClass>
    
    function Component() {
      return <MyClass foo={"123"} /> // fixed
    }
    
    TypeScript playground example (same example from #60162)

The workaround in point 3 is cumbersome, but that is the only way.

The idea in https://github.com/microsoft/TypeScript/issues/60162 would help make the mapped type workaround simpler, but would not solve the actual JSX issue.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

No se nombran archivos del repositorio ni pruebas. Empieza comparando el comportamiento de comprobación de tipos de JSX en los ejemplos vinculados del playground con el issue relacionado #60162 y, después, sigue el tratamiento que hace el compilador de TypeScript de las props de JSX y de los tipos de getter/setter. Se considera terminado cuando JSX acepta valores permitidos por el setter de una propiedad sin cambiar el JavaScript emitido.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
typescript
Área
compilers
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
30/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.