Il tipo generico su una classe Typescript può essere omesso
Usare Typescript con le opzioni predefinite del compilatore è piuttosto severo su cosa è permesso o no - come valori nulli, attributi di classe non inizializzati nel costruttore. Ma quando si tratta di generici, è possibile definire un tipo generico per una classe e poi creare una nuova classe senza specificare il 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
È possibile considerare new Foo() come un'istruzione sbagliata?
Come specificato sopra, sto usando le opzioni predefinite del compilatore che non permetterebbero di aggiungere un attributo extra a: T che non verrebbe mai inizializzato.
Risposta n. 1
Non puoi rendere l'omissione di T nel costruttore un errore (beh, probabilmente potresti, ma avresti bisogno di un po' di magia dei tipi condizionali e di un costruttore con almeno un argomento)
Puoi rendere la classe inutilizzabile se non viene fornito alcun argomento usando un valore predefinito per il parametro di tipo. Un valore predefinito di never farà al caso tuo.
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
Puoi anche usare un overload del costruttore e tuple nei parametri rest per creare un costruttore che genererà un errore se ometti il parametro di tipo (cioè il parametro di 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
Risposta n. 2
Oltre alle altre risposte, vorrei sottolineare che TSLint ha una regola specificamente contro questo caso: no-inferred-empty-object-type
Abilitare questa regola farà sì che TSLint segnali un errore quando TypeScript deduce {} come generico (simile al flag del compilatore noImplicitAny, ma solo per i generici).
Questo sembra essere esattamente ciò che vuoi.
