Tslint: Conflicto de reglas 'no-inferable-types' y 'typedef'

Creado en 3 oct. 2015  ·  33Comentarios  ·  Fuente: palantir/tslint

Hola de nuevo,

No estoy seguro de si se trata de un problema o de una decisión de diseño, pero puedo ver un conflicto entre las reglas no-inferrebale-types y typedef .

Ex.

function fn(): void {
    for (let i = 0; i < 100; i++) {
        console.log(i);
    }
}

Fragmento de https://github.com/palantir/tslint/blob/master/docs/sample.tslint.json :

 "typedef": [true, ...],
 "no-inferrable-types": true,

Cuando tengo estas dos reglas activadas, obtengo:

error (typedef) test.ts[2, 12]: expected variable-declaration: 'i' to have a typedef

Agregar la anotación de tipo number a la variable i provoca a su vez el siguiente error:

error (no-inferrable-types) test.ts[2, 14]: LHS type (number) inferred by RHS expression, remove type annotation

¿Hay alguna forma de que estas dos reglas coexistan entre sí?

Por ejemplo, quiero tener variables inferibles directamente declaradas con tipo primitivo (como dice el documento de reglas: number , boolean o string ), pero por otro lado, quiero para forzar typedefs en tipos no primitivos.

Gracias,

o

P1 Enhancement 🌹 R.I.P. 🌹

Comentario más útil

:+1: Idealmente (en mi opinión) me gustaría una forma de decir "siempre se requiere un typedef, a menos que el tipo sea inferible". Cosa que no creo que sea posible ahora mismo.

Todos 33 comentarios

Buena captura, gracias por el aviso. Agregué la regla no-inferrable-types sin pensar en cómo podría entrar en conflicto con la regla typedef , ¡ups! Por ahora recomendaría desactivar uno de los dos, o usar solo algunas opciones de la regla typedef .

A más largo plazo, creo que querremos integrar no-inferrable-types en la regla typedef o querremos al menos que TSLint detecte configuraciones conflictivas como tener ambas reglas activadas.

Estoy enfrentando el mismo problema.
He desactivado los tipos no inferibles por ahora.

Sí, lo mismo aquí, me gustaría tener la capacidad de que ambas reglas coexistan.
No me gustaría que la regla typedef se active si se puede inferir el tipo de variable.
es decir, los "tipos no inferibles" deben tener prioridad sobre "typedef"

+1

let id: number = 0;
for (let job: string of NAMES_PROFFESSIONS) {
     /** some code */
     id++;
}

(tipos no deducibles) Tipo LHS (número) inferido por expresión RHS, eliminar anotación de tipo

+1

¿Su definición de tipos "inferibles" incluye asignaciones de constructores?

// BAD (this hurts my eyes to read)
let labels: Map<string, string> = new Map<string, string>();
// GOOD (type is obvious)
let labels = new Map<string, string>();

pero también...

// BAD (in a diff, it's not obvious what this type is)
let labels = this.buildLabels();
// GOOD
let labels: Map<string, string> = this.buildLabels();

Sí, es peligroso. Si quiero simplificar mi código y evitar el uso de declaración de tipo para variables inicializadas directamente, no puedo hacer esto estrictamente y esto lleva a tal cosa:

let x = 2;
let y;
let z: number;

x = 1;
y = 1;
z = 1;
x = 's'; // Type 'string' is not assignable to type 'number'
y = 's'; // It's OK
z = 's'; // Type 'string' is not assignable to type 'number'

Puede ser una opción muy útil permitir la declaración de tipo de omisión solo para variables inicializadas.

… y realmente no solo para tipos primitivos, como dice @pgonzal !
Mira esto, es terrible:

const onChange: () => void = () => this.update();

:+1: Idealmente (en mi opinión) me gustaría una forma de decir "siempre se requiere un typedef, a menos que el tipo sea inferible". Cosa que no creo que sea posible ahora mismo.

Me encontré con esto e hice una ignore-params que me ayudó en mi caso. Quiero forzar typedefs para todos los parámetros de método/función, incluso cuando se pueden inferir fácilmente.

Ver PR: #1190 si quieres probarlo

Ha pasado un tiempo desde que se envió el problema original. ¿La opción recomendada en este momento es deshabilitar no-inferrable-types e incluir el tipo en todo? Cualquier otra cosa para probar y habilitar y combinar tanto no-inferrable-types como typedef parece un truco y da como resultado un montón de advertencias sin sentido. Esperando una mejor solución en un futuro próximo.

@corydeppen Tenga en cuenta los 8 pulgares hacia arriba en la sugerencia de @englercj , arriba. No está claro qué significa "combinar" en su comentario "parece un truco". Si quiere decir "usar juntos en tslint.json , entonces, sí. Pero "combinar" un argumento optional-inferrable-types en typedef sería genial (al menos, para 9 de nosotros).

¿Podemos obtener una actualización sobre esto, por favor?

Creo que la mejor manera de manejar esto es desaprobar el no-inferrable-types y simplemente pasar un objeto de opción a typedef para ignorar la falta de definiciones de tipo si el tipo es inferible de acuerdo con ciertos patrones, como initialized , initialized primitives , call signatures y otros patrones que satisfarían nuestras necesidades como desarrolladores.

Para mí esto tiene más sentido, porque siempre debe haber un typedef, a menos que haya algo que te diga cuál es el tipo de función. Y también sería configurable, porque tal vez queramos que el properties inicializado en una clase tenga un tipo inferible, pero no para el call signatures por ejemplo.

Sería genial si alguien pudiera colaborar para solucionar esto. Hasta entonces, nos vemos obligados a elegir entre "no hay suficientes declaraciones de tipos para ser legibles" versus "lleno de demasiadas declaraciones de tipos".

Este problema ha estado abierto desde el 3 de octubre de 2015; desde entonces, mi equipo ha creado alrededor de 2000 archivos fuente de TypeScript que están repletos de demasiadas declaraciones de tipos.

El typedef acepta una configuración. Entonces, tal vez solo otra configuración solo para ignorar la definición de tipo si el tipo es inferible, lo que significa

Simplemente escriba donde no se esté inicializando.

Parece que debido a que no hay un consenso claro sobre cómo abordar el problema, no se está logrando ningún progreso. Ejemplo de comentario: https://github.com/theia-ide/theia/issues/356#issuecomment -319350833

Sospecho que todos estamos de acuerdo en que cualquier solución es mejor que dejar las cosas como están. Si cree que cualquier cambio en el status-quo con respecto a este tema es bueno, por favor 👍 este comentario. Si tiene los conocimientos suficientes para crear un PR para solucionar este problema, ayúdenos a todos ❤️.

Aceptaría un PR para:

  • agregue una opción a typedef que le permita ignorar los casos en los que no-inferrable-types dice que no proporcione un tipo

El typedef acepta una configuración. Entonces, tal vez solo otra configuración solo para ignorar la definición de tipo si el tipo es inferible, lo que significa 'Simplemente escriba donde no se esté inicializando'.

La regla typedef es para personas a las que les gusta tener definiciones de tipo explícitas en su base de código. Si desea que el comportamiento anterior "simplemente escriba donde no se esté inicializando", es mejor que deshabilite typedef y se asegure de tener noImplictAny habilitado como una opción del compilador de TypeScript.

También existe el caso complicado en el que algunas cosas que se inicializan necesitan un typedef de todos modos, como en el siguiente fragmento:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

Además, mientras arreglamos esto, quería mencionar que es probable que existan algunas reglas excelentes de terceros, como no-unnecessary-type-annotation (https://github.com/ajafff/tslint-consistent-codestyle/blob/ master/docs/no-unnecessary-type-annotation.md), por ejemplo. Si alguien conoce otras reglas de terceros que proporcionen el comportamiento deseado, publíquelas aquí y podemos recomendarlas oficialmente o adoptarlas en el núcleo si tiene sentido.

@JKillian gracias por la recomendación, creo que eso es lo que quería. Hay una publicación muy buena sobre cómo evitar el tipo any : no use "naked any", cree una "cualquier interfaz" en su lugar.

Acerca de:

interface Literal {
    field: "value"
}

const literal0 = {
    field: "value",
};
const literal1: Literal = {
    field: "value",
};

const func = (obj: Literal) => { };
func(literal0);  // Error! Type 'string' is not assignable to type '"value"'.
func(literal1);

No veo cómo esto podría ser un comportamiento no deseado ni un caso complicado. Quiere asegurarse de que obj tenga una propiedad field con valor value , e incluso cuando esté inicializando literal0 con una propiedad que parezca la restricción , podría modificar eso a otra cadena.

Sé que no es un buen caso de uso, pero en la mayoría de los casos cuando usas un literal, probablemente quieras ese literal, no un primitivo.

Tengo la siguiente configuración:
json "no-inferrable-types": true, "typedef": [true, "call-signature", "parameter"],
Y este código:
javascript private static readonly DEVICE_UID: string = 'device_uid'; private static readonly DEVICE_PLATFORM: string = 'browser'; private static readonly AGENT_DEFAULT_ICON = 'http://localhost:3000/icon.png';

¿Por qué no recibo error en las dos primeras declaraciones?

@sandrocsimas Interesante, pero creo que fuera de tema; AFAICT ese problema no está relacionado con este problema. Te sugiero que inicies otro número (¡fwiw!).

@estaub , sí lo haré. Obtengo el mismo comportamiento incluso sin la regla typedef.

@sandrocsimas eso se debe a que es una propiedad de solo lectura, y Typescript infiere su tipo como un literal. Escribiéndolo como una cadena, está diciendo que debería tener una cadena, no necesariamente tendrá ese valor literal y el valor no debería cambiar estáticamente.

Sería bueno tener una regla 'require-typedef-except-inferable'.

@FiretronP75 como dijo @JKillian , esa es solo la opción noImplicitAny del TSC.

@michaeljota gracias, no me di cuenta de que la opción noImplicitAny del compilador ofrece excepciones para inferibles. Sin embargo, todavía sería bueno tenerlo en tslint, por la opción de convertirlo en una advertencia en lugar de interrumpir la compilación, y por tener las banderas de comentarios de tslint.

Veo por qué esto sería algo deseado, pero teniendo no-unused-variables como ejemplo, no creo que los casos de uso cubiertos por TSC vayan a ser respaldados por el equipo de TSLint. Sé que no es lo mismo un _error de linter_ que un _error de compilador_ pero al final, ambos se tratan de escribir mejor código. Hoy en día, con soluciones como Webpack o Parcel que le permiten compilar y ejecutar el código incluso con errores de TSC, no veo esto como un problema real.

¿Se ha solucionado esto en la última versión?

Todavía no creo que esto esté en la hoja de ruta. Debería considerar usar noImplicitAny del TSC

☠️ ¡Ha llegado el momento de TSLint! ☠️

TSLint ya no acepta la mayoría de las solicitudes de funciones según el n.º 4534. Consulte typescript-eslint.io para conocer la nueva y brillante forma de aplicar pelusa a su código TypeScript con ESLint . ✨

¡Fue un placer abrir código con todos ustedes!

🤖 ¡Bip boop! 👉 TSLint está en desuso 👈 _(#4534)_ ¡y deberías cambiar a TypeScript-eslint ! 🤖

🔒 Este problema se está bloqueando para evitar más discusiones innecesarias. ¡Gracias! 👋

¿Fue útil esta página
0 / 5 - 0 calificaciones