Versão TypeScript: 2.3.2
Código
// example.js
var Person = function (firstNameOrPojo, lastName) {
if (typeof firstNameOrPojo === "string") {
this.firstName = firstNameOrPojo;
this.lastName = lastName;
} else {
return new Person(firstNameOrPojo.firstName, firstNameOrPojo.lastName);
}
};
Person.prototype.greet = function greet() {
return `Hello, I am ${this.firstName} ${this.lastName}.`;
};
var fred = new Person({firstName: "Fred", lastName: "Flintstone"});
console.log(fred.greet());
Comportamento esperado:
Eu esperaria que tsc
compilasse este código sem erros ou avisos, especialmente considerando que o tipo retornado sempre corresponde ao tipo esperado.
Em JavaScript, é possível que uma função construtora retorne um objeto. Quando isso é feito, o objeto retornado se torna o resultado de toda a expressão new
(consulte a etapa 3 nesta documentação MDN para o novo operador ).
Preocupado com os tipos, posso ver por que o compilador TypeScript hesitaria em oferecer suporte a essa peculiaridade da linguagem JavaScript. Afinal, o compilador teria que verificar se o valor explicitamente retornado é o mesmo tipo que seria retornado do construtor se ele retornasse undefined
(o caso usual). Acho que isso deve ser apoiado, porque:
Esta é uma técnica de JavaScript útil e popular
O código acima funciona perfeitamente no Node.js e no navegador:
$ node example.js
Hello, I am Fred Flintstone.
Comportamento real:
tsc
emite um erro ao verificar este código:
$ tsc --allowJs --checkJs --outDir ./dist example.js
example.js(8,16): error TS2350: Only a void function can be called with the 'new' keyword.
O tipo é realmente calculado corretamente, independentemente do que você retornar; o compilador sabe como usar o tipo de retorno quando chamado como uma função e o tipo de instância quando usado como um construtor. o erro é o que precisa ser corrigido para o arquivo .js. o padrão ainda não é permitido para um arquivo .ts (uma vez que erramos no lado conservador aqui).
+1
Especialmente agora que temos Proxy
, existem bons comportamentos que podemos implementar retornando um proxy em vez da instância da classe diretamente. Mas isso não será possível a menos que possamos inferir ou especificar o tipo de retorno do construtor.
se você pudesse colocar
get(target, name) {}
e
set(target, name, value) {}
dentro do construtor de classe para substituir os operadores de atribuição de propriedade para (todas as propriedades de) Object / Array, então ... javascript não seria insuficiente.
[Caso contrário, seria suficiente retornar o novo Proxy com as funções de manipulador.]
Comentários muito úteis
+1
Especialmente agora que temos
Proxy
, existem bons comportamentos que podemos implementar retornando um proxy em vez da instância da classe diretamente. Mas isso não será possível a menos que possamos inferir ou especificar o tipo de retorno do construtor.