El tipo genérico en la clase de Typescript se puede omitir
Usar Typescript con las opciones predeterminadas del compilador es bastante estricto sobre lo que está permitido o no, como los valores nulos, los atributos de la clase que no se inicializan en el constructor. Pero cuando se trata de genéricos, es posible definir un tipo genérico para una clase y luego crear una nueva clase sin especificar el tipo.
class Foo<T> {
bar(item: T): void {
console.log('typeof T: ', typeof item)
}
}
const foo1 = new Foo<string>() // T specified
foo1.bar('hello')
foo1.bar(6) // error TS2345: Argument of type '6' is not assignable to parameter of type 'string'
const foo2 = new Foo() // T missing
foo2.bar('hello')
foo2.bar(6) // works with no complaint
¿Es posible considerar new Foo() como una declaración incorrecta?
Como se especifica arriba, estoy usando las opciones predeterminadas del compilador, las cuales no permitirían agregar un atributo extra a: T que nunca sería inicializado.
Respuesta #1
No puedes hacer que la omisión de T en el constructor sea un error (bueno, probablemente podrías, pero necesitarías algo de magia de tipos condicionales y un constructor con al menos un argumento)
Puedes hacer que la clase sea inutilizable si no se proporciona ningún argumento usando un valor predeterminado para el parámetro de tipo. Un valor predeterminado de never hará el truco.
class Foo<T = never> {
bar(item: T): void {
console.log('typeof T: ', typeof item)
}
}
const foo1 = new Foo<string>() // T specified
foo1.bar('hello')
foo1.bar(6) // error TS2345: Argument of type '6' is not assignable to parameter of type 'string'
const foo2 = new Foo() // T missing
foo2.bar('hello') // err
foo2.bar(6) // err
También puedes usar una sobrecarga de constructor y tuplas en los parámetros rest para crear un constructor que dará un error si omites el parámetro de tipo (es decir, el parámetro de tipo es never)
class Foo<T = never> {
constructor(...a: T extends never ? ['No T was specified']:[])
constructor() {
}
bar(item: T): void {
console.log('typeof T: ', typeof item)
}
}
const foo1 = new Foo<string>() // T specified
foo1.bar('hello')
foo1.bar(6) // error TS2345: Argument of type '6' is not assignable to parameter of type 'string'
const foo2 = new Foo() // T missing, error!
foo2.bar('hello')//err
foo2.bar(6) //err
Respuesta #2
Además de las otras respuestas, me gustaría señalar que TSLint tiene una regla específicamente contra este caso: no-inferred-empty-object-type
Habilitar esta regla hará que TSLint se queje cuando TypeScript infiera {} como un genérico (similar a la opción del compilador noImplicitAny, solo para genéricos).
Esto parece ser exactamente lo que quieres.
