Usando immutable.js em Typescript

Imutabilidade <vs> tipo de segurança

Meu projeto mais recente me abençoou com a chance de trabalhar com Angular2 e Typescript, isso é uma grande mudança em relação a escrever no babel transpilado ES6 como estou acostumado.
Os tipos fornecem ferramentas fortes – Webstorm 12 no meu caso – parece “saber” o que estou fazendo e oferece grande ajuda, sugerindo autocompletar e marcando meus erros.
Arquitetura de fluxo de dados de front-end atual, como Redux e @ ngrx / store beneficia muito para o uso de estruturas de dados Imutáveis.
No entanto, isso quebra a capacidade do Typescript de sugerir nomes de propriedades.

o choque de titãs

vamos examinar:

um hash simples declarado aqui


const myHash = {
property
:"value"
}

fará o IDE sugerir a propriedade interna ao escrever a referência do objeto (mesmo sem um tipo),
então, quando você escrever myHash.

você obterá um menu suspenso no qual “propriedade” será a primeira opção

é claro que você pode obter resultados ainda melhores

interface myHash{
property
:string
}
const myHash<myHash> = {property:"value"}

//in use
myHash
.property = 5;
//the IDE will mark the above line as error (and indeed the TS compiler will error too)

Mas quando você introduz a imutabilidade, o uso de = para definir valores é limitado a atribuir novas instâncias


const myHash = Immutable.fromJS({property:"value"})


myHash
.property = 5 // Error : immutable can not be changed
//even worse - myHash does not have autocomplete for .property.... it does not have this property
console
.log(myHash.property) // undefined

isso ocorre porque Immutable.fromJS cria um immutable.Map ao usá-lo com um argumento POJO de origem (objeto javascript antigo simples)

a maneira certa de usá-lo é esta:

myHash.get('property'); // value
let newValueHash = myHash.set('property','newValue');

usar o nome da propriedade como argumento de string elimina a ajuda do typescript e de todas as novas ferramentas IDE baseadas nele.

Grave para o resgate

Um comportamento muito melhor pode surgir usando Immutable.Record:

const myHashRecord = new Immutable.Record({property:'defaultValue'})
let myHash = new myHashRecord();
console
.log(myHash.property) // defaultValue
//notice that the property can be accessed like in POJO
//but for setting new value we need to use it like before in the Map's case
myHash
.property = 555; //Error
let newHashValue = myHash.set('property'','newValue') //works

portanto, isso nos ajuda em relação ao preenchimento automático, mas não:
1. nos ajuda com a necessidade de escrever os nomes das propriedades como strings no caso de definir novas propriedades
2. nos protege de usar o tipo errado ao definir um novo valor

Eu descobri que uma combinação entre um Immutable Record e uma Typcript Class pode pelo menos nos dar o segundo ponto feito, ela nos faz escrever nossa lista de propriedades duas vezes, mas eu acho que vale a pena digitar.

let demoRecord = Immutable.Record({
property
:'defaultValue',
index
:0,
works
:true,
valueList
:Immutable.List([])
});

export class Demo extends demoRecord {
property
:string;
index
:number;
truth
:boolean;
valueList
:Immutable.List<YourMoreComplexTypeHere>
}

let demo = new Demo();

agora, ao escrever demo. o IDE irá sugerir a você suas propriedades, bem como os métodos de protótipo do Registro, como .set, .toJS etc.,
mas o IDE também saberá que a propriedade “index” é um número e que “true” é um booleano.
Claro, você pode usar tipos mais complexos com base em suas definições de tipo e interface.

Mais pensamentos

a biblioteca Immutable.js está vindo do Facebook, Typescript é tecnologia da Microsoft, construímos sobre os ombros de gigantes aqui, eu me pergunto por que temos que fazer tais truques para fazer os dois funcionarem bem juntos, e isso ainda não é perfeito.
há um problema sobre esse assunto no repo do Facebook , lembro-me de ter visto um também no repo da Microsoft, mas não consegui encontrá-lo hoje.

Existem também outras bibliotecas Immutable como alguns dos comentários sobre esse tópico apontam, a imutabilidade pode ser alcançada via Object.defineProperty escrevendo getters apenas, ou pode-se usar geratos de código de tipificação como ts-immutable, mas eu sugiro que o futuro deve ser mais simples neste caso
, ficarei muito feliz em ouvir sua opinião sobre o assunto.