reactjs - Kan TypeScripts `readonly` fullt ut erstatte Immutable.js?


Jeg har jobbet med et par prosjekter som bruker React.js. Noen av dem har brukt Flux, noen Redux og noen var bare vanlige React-apper som bruker Context.

Jeg liker virkelig måten Redux bruker funksjonelle mønstre på. Imidlertid er det stor sjanse for at utviklere utilsiktet muterer staten. Når man søker etter en løsning, er det egentlig bare ett svar - Immutable.js. For å være ærlig, hater jeg dette biblioteket. Det endrer helt måten du bruker JavaScript på. Dessuten må det implementeres gjennom hele applikasjonen, ellers ender du opp med merkelige feil når noen objekter er vanlige JS-objekter og noen er Immutable-strukturer. Eller så begynner du å bruke .toJS(), som igjen er veldig veldig dårlig.

Nylig har en kollega av meg foreslått å bruke TypeScript. Bortsett fra typesikkerheten, har det en interessant funksjon - du kan definere dine egne datastrukturer, som har alle feltene merket som readonly. En slik struktur ville i hovedsak være uforanderlig.

Jeg er ikke ekspert på verken Immutable.js eller TypeScript. Men løftet om å ha uforanderlige datastrukturer inne i Redux-butikken uten å bruke Immutable.js virker for godt til å være sant. Er TypeScript sin readonly en passende erstatning for Immutable.js? Eller finnes det noen skjulte problemer?

Svar #1

Selv om det er sant at readonly-modifikatoren i TypeScript kun eksisterer på designtype og ikke påvirker kode under kjøring, gjelder dette for hele typesystemet. Det vil si, ingenting hindrer deg under kjøring fra å tilordne et tall til en variabel av typen string. Så det svaret er egentlig litt villedende... hvis du får en advarsel på designtid om at du prøver å endre noe merket som const eller readonly, kan det muligens eliminere behovet for omfattende kjøringstidskontroller.

Men det er en viktig grunn til hvorfor readonly er utilstrekkelig. Det er et uløst problem med readonly, som er at typer som kun avviker i sine readonly-attributter, for øyeblikket (per TS3.4) kan tilordnes til hverandre. Dette lar deg enkelt bryte gjennom den beskyttende readonly-skallet til en hvilken som helst egenskap og tukle med innmaten:

type Person = { name: string, age: number }
type ReadonlyPerson = Readonly<Person>;

const readonlyPerson: ReadonlyPerson = { name: "Peter Pan", age: 12 };
readonlyPerson.age = 40; // error, "I won't grow up!"

const writablePerson: Person = readonlyPerson; // no error?!?!
writablePerson.age = 40; // no error!  Get a job, Peter.

console.log(readonlyPerson.age); // 40

Dette er ganske dårlig for readonly. Inntil det blir løst, kan det hende du finner deg selv enig med en tidligere som rapporterte et problem, som opprinnelig kalte problemet «readonly-modifikatorer er en spøk» 🤡.

Selv om dette blir løst, kanskje ikke readonly dekker alle bruksområder. Du må også gå gjennom alle grensesnitt og typer i bibliotekene dine (eller til og med standardbibliotekene) og fjerne metoder som endrer tilstand. Så alle bruk av Array må endres til ReadonlyArray og all bruk av Map må endres til ReadonlyMap, osv. Når du har gjort dette, vil du ha en ganske typesikker måte å representere uforanderlighet på. Men det er mye arbeid.

Uansett, håper det hjelper; lykke til!

Svar #2

Hensikten med Immutable.js er ikke å forhindre en utvikler i å gjøre en ulovlig mutasjon på kompileringstidspunktet. Det gir et praktisk API for å lage kopier av et objekt med noen av egenskapene endret. Det faktum at du får typesikkerhet på objekter som du håndterer med immutable.js er i utgangspunktet bare en bieffekt av å bruke det.

Typescript er «bare» et typesystem. Det implementerer ingen av funksjonene som Immutable.js har for å lage kopier av uforanderlige objekter. Alt det gjør når man erklærer en variabel som readonly, er å sjekke under kompilering at du ikke endrer den. Hvordan du utformer koden din for å håndtere uforanderlighet, er ikke omfanget av et typesystem, og du vil fortsatt trenge en måte å håndtere det på.

React sikrer immutabilitet ved å tilby en metode setState i stedet for å endre tilstandsobjektet direkte. Den tar seg av å slå sammen de endrede egenskapene for deg. Men hvis du for eksempel bruker Redux, kan du ønske en praktisk løsning for å håndtere immutabilitet også. Det er det Immutable.js gir, og TypeScript vil aldri gjøre, og det er uavhengig av om du liker API-en eller ikke.

Relaterte artikler