O seguinte programa de digitação é aceito:
class C {
static length () { return "twelve"; }
}
No entanto, no código gerado:
var C = (function () {
function C() {
}
C.length = function () {
return "twelve";
};
return C;
})();
Aqui, é feita uma tentativa de atribuir à propriedade length
de uma função. Isso não funciona (pelo menos no Firefox e Chrome), fazendo com que as chamadas subsequentes de C.length()
travem. Talvez a chamada de uma função de classe estática length
deva apenas ser proibida?
Migrado do codeplex problema # 1260 .
Corri para isso recentemente. :(
Além disso, alguns outros não são permitidos, por exemplo, o código a seguir deve apresentar erro (se fizermos esse recurso):
class C {
static name = 'something';
static arguments = 'args';
static caller = 'caller';
}
console.log(C.name); // 'C'
console.log(C.arguments); // null
console.log(C.caller); // null
No entanto, nem todos são estelares.
Não acho que as propriedades name
, caller
e length
são viáveis. Eles são propriedades somente leitura e não podem ser substituídos. Todas as atribuições a eles serão ignoradas.
@tinganho concordou
Ok, mas como as pessoas pegam esse tipo de erro de vez em quando, acho que o TS deveria notificá-las sobre fazer algo errado. É porque propriedades como name
ou length
são tão naturais de se ter em mente que as pessoas tentarão redefini-las repetidas vezes.
Pode ser porque Lengh, nome já está definido.
Vou tentar trabalhar nisso. Além do que já foi mencionado, existem mais nomes de propriedades que não deveriam ser permitidos?
Até agora eu vejo:
comprimento, nome, argumentos, chamador
O que exatamente deve acontecer quando alguém tenta definir uma propriedade estática com um dos nomes proibidos? Erro do compilador? Aviso visível para o usuário?
Eu sou novo nisso, então se eu estiver faltando alguma coisa, então alguma orientação seria apreciada. : +1:
Por que não compilar
class C {
static name = 'something';
static arguments = 'args';
static caller = 'caller';
}
console.log(C.name); // 'C'
console.log(C.arguments); // null
console.log(C.caller); // null
para algo como
var C = (function () {
function C() {
}
C.__statics = {
name: 'something',
arguments: 'args',
caller: 'caller'
};
return C;
})();
console.log(C.__statics.name); // 'something'
console.log(C.__statics.arguments); // 'args'
console.log(C.__statics.caller); // 'caller'
Também surgiu uma pergunta sobre stackoverflow: http://stackoverflow.com/a/34644236/390330 : rose:
@zerkms, por favor, não poste o mesmo comentário em dois lugares; é confuso.
Às vezes, você não pode reescrever nomes arbitrariamente em um sistema de tipo estrutural.
Considere algum código como este
interface HasName {
name: string;
}
class Foo {
static name = 'fooClass';
}
let bar: HasName = { name: string };
let q = Math.random() > 0.5 ? Foo : bar;
console.log(q.name);
@RyanCavanaugh é um bom exemplo, de fato (eu não desenvolvo em TS, mas nossa - seu sistema de tipos é estranho assim que trata este código como válido).
Se não é possível transpilá-los sem risco, talvez devêssemos apenas proibi-los?
Se não é possível transpilá-los sem risco, talvez devêssemos apenas proibi-los?
Definitivamente, não alterando o transpile, apenas tornando-o um erro de compilação: rose:
[...] talvez devêssemos apenas desautorizá-los?
Algum desenvolvedor empreendedor deve nos enviar um PR! :piscadela:
Por que não usar Object.defineProperty
?
por exemplo
class C {
static length() { return "twelve"; }
}
seria transplicado para algo como
var C = (function () {
function C() {
}
Object.defineProperty(C, "length", {
value: function () { return "twelve"; },
writable: true
});
return C;
}());
@ nicolo-ribaudo Isso realmente funciona. Minha opinião: mas eu prefiro ver um erro em vez de tal transpile. O TypeScript geralmente se inclina para o erro elegante em vez de _fixar o JavaScript_: rose:
TypeScript geralmente se inclina para o lado do erro gracioso em vez de corrigir o JavaScript
A ideia do TS não é consertar o JS preenchendo as lacunas que ele não pode e nunca será capaz.
A ideia do TS não é consertar o JS preenchendo as lacunas que ele não pode e nunca será capaz.
sim. Mas entendendo como funciona o JavaScript. Tome um exemplo de null
e undefined
. O TypeScript opta por entender ambos (em vez de consolidá-lo em uma única coisa como o Dart faz https://www.dartlang.org/docs/synonyms/). O TypeScript fornece erros (em vez de corrigi-los no transpile) se você usar o padrão JavaScript errado: rose:
Minhas opiniões são minhas e não são endossadas por ninguém além de mim: rose:
Enquanto isso, o suporte nativo ES6 / 2015 chegou ao Chrome e ao Firefox. Se observarmos como eles lidam com o problema nativamente, chega perto do que @ nicolo-ribaudo e eu propomos (consulte # 9778).
Snippet para ilustrar o comportamento nativo:
class Foo {
constructor() {}
}
class Bar {
static length() {}
static name() {}
static caller() {}
}
Foo.name = "FooChanged";
Bar.name = "Baz";
console.log(Foo.name) // Logs "Foo". Foo.name remains unwritable
console.log(Bar.name) // Logs "Baz". Bar.name became writable
Com relação ao que @tinganho escreveu anteriormente sobre a somente leitura de name
, length
e caller
, podemos observar para as implementações nativas que as propriedades são graváveis em uma função de construtor uma vez nós definimos qualquer um deles como um membro de classe estático (sinta-se à vontade para revisar ou modificar meus avisos recentes no MDN sobre suposições perigosas sobre Function.name
para obter um nome de classe, por causa disso).
Portanto, usar Object.defineProperty
como sugerido por @ nicolo-ribaudo iria emular o comportamento nativo com precisão. Algo que precisa ser considerado é que algumas versões de navegador mais antigas, mas compatíveis com ES5, definiram as propriedades como configurable: false
. Portanto, tentar torná-los writable: true
irá falhar para eles (por exemplo, veja a configurabilidade de Function.name )
Para resumir, minha opinião sobre o problema foi:
Object.defineProperty()
para o destino de compilação es3
. Sem Object.defineProperty
, executar o código ES3 em um ambiente ES5, entretanto, teria o problema somente leitura. Portanto, precisamos de um erro de compilação para o destino es3
Object.defineProperty()
e writable: true
para o destino de compilação es5
e emita um aviso / erro informando que o uso desses nomes de propriedade pode causar erros nos navegadores x of version <= y
sugerindo que, se esses navegadores precisarem ser suportados, a opção mais segura seria escolher outro nome.Independentemente da saída da compilação, acho que qualquer tipo de mensagem adicional seria melhor do que a situação atual (TS 1.8.10), onde não temos nenhuma dica sobre possíveis problemas com a saída do compilador.
Editar : cortado adicionado
@RyanCavanaugh : você poderia revisitar este problema para o marco TS 2.0.1. A solução parece simples, mas dependendo de qual opção você escolher, a saída do emissor pode precisar mudar (veja meu comentário anterior). O lançamento do TS 2.0, então, pode ser melhor incluir a correção.
As tags no PR indicam que a equipe do TypeScript, que tem recursos limitados, está deixando isso em aberto para que a comunidade resolva. Se você quiser que esse problema seja resolvido, alguém na comunidade mais ampla terá que lidar com isso até que a equipe principal do TypeScript sinta que tem espaço suficiente no backlog para colocá-lo em um lançamento (o que provavelmente seria um longo tempo).
@kitsonk Obrigado por explicar o rótulo de relações públicas. Acho que entendi isso. O que sugeri foi reavaliar se ainda é a maneira certa de lidar com o problema. Propriedades estáticas de classe chamadas _nome_ ou _comprimento_ não são tão improváveis de acontecer e o TS produz uma saída errônea para isso. Portanto, eu nem chamaria o problema de "caso extremo".
Considero as propriedades estáticas no centro da linguagem e, mesmo que ainda não haja solicitações de pull, soluções para o problema foram apresentadas neste tópico.
No entanto, irei avaliar se posso fornecer um PR, mas devo admitir que ainda não tenho muito conhecimento sobre as fontes do TS e temo que o TS 2.0 seja lançado antes.
Comentários muito úteis
Enquanto isso, o suporte nativo ES6 / 2015 chegou ao Chrome e ao Firefox. Se observarmos como eles lidam com o problema nativamente, chega perto do que @ nicolo-ribaudo e eu propomos (consulte # 9778).
Snippet para ilustrar o comportamento nativo:
Com relação ao que @tinganho escreveu anteriormente sobre a somente leitura de
name
,length
ecaller
, podemos observar para as implementações nativas que as propriedades são graváveis em uma função de construtor uma vez nós definimos qualquer um deles como um membro de classe estático (sinta-se à vontade para revisar ou modificar meus avisos recentes no MDN sobre suposições perigosas sobreFunction.name
para obter um nome de classe, por causa disso).Portanto, usar
Object.defineProperty
como sugerido por @ nicolo-ribaudo iria emular o comportamento nativo com precisão. Algo que precisa ser considerado é que algumas versões de navegador mais antigas, mas compatíveis com ES5, definiram as propriedades comoconfigurable: false
. Portanto, tentar torná-loswritable: true
irá falhar para eles (por exemplo, veja a configurabilidade de Function.name )Para resumir, minha opinião sobre o problema foi:
Object.defineProperty()
para o destino de compilaçãoes3
. SemObject.defineProperty
, executar o código ES3 em um ambiente ES5, entretanto, teria o problema somente leitura. Portanto, precisamos de um erro de compilação para o destinoes3
Object.defineProperty()
ewritable: true
para o destino de compilaçãoes5
e emita um aviso / erro informando que o uso desses nomes de propriedade pode causar erros nos navegadoresx of version <= y
sugerindo que, se esses navegadores precisarem ser suportados, a opção mais segura seria escolher outro nome.Independentemente da saída da compilação, acho que qualquer tipo de mensagem adicional seria melhor do que a situação atual (TS 1.8.10), onde não temos nenhuma dica sobre possíveis problemas com a saída do compilador.
Editar : cortado adicionado