O tipo genérico em uma classe TypeScript pode ser omitido
Usar Typescript com as opções padrão do compilador é bastante rígido sobre o que é permitido ou não - como valores nulos, atributos de classe não sendo inicializados no construtor. Mas quando se trata de genéricos, é possível definir um tipo genérico para uma classe e então criar uma nova classe sem especificar o 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
É possível considerar new Foo() como uma declaração errada?
Como especificado acima, estou usando as opções padrão do compilador, que não permitiriam adicionar um atributo extra a: T que nunca seria inicializado.
Resposta #1
Você não pode tornar a omissão de T no construtor um erro (bem, você provavelmente pode, mas precisaria de alguma mágica de tipo condicional e um construtor com pelo menos um argumento)
Você pode tornar a classe inutilizável se nenhum argumento for fornecido usando um valor padrão para o parâmetro de tipo. Um valor padrão de never fará o truque.
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
Você também pode usar uma sobrecarga de construtor e tuplas em parâmetros rest para criar um construtor que dará um erro se você omitir o parâmetro de tipo (ou seja, o parâmetro de tipo é 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
Resposta #2
Além das outras respostas, gostaria de apontar que o TSLint possui uma regra especificamente contra este caso: no-inferred-empty-object-type
Ativar esta regra fará com que o TSLint reclame quando o TypeScript inferir {} como um genérico (similar à flag do compilador noImplicitAny, mas apenas para genéricos).
Isto parece ser exatamente o que você quer.
