TypeScript 2.3 implementoval výchozí výchozí hodnoty obecných parametrů které umožňují určit výchozí typy pro parametry typu v obecném typu.
V tomto příspěvku chci prozkoumat, jak můžeme těžit z obecných výchozích parametrů migrací následující komponenty React z JavaScriptu (a JSX) na TypeScript (a TSX):
class Greeting extends React.Component {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Nebojte se, nemusíte znát React, abyste mohli sledovat!
#Vytvoření definice typu pro třídu komponent
Začněme vytvořením definice typu pro Component
třída. Každá komponenta React založená na třídě má dvě vlastnosti props
a state
, oba mají libovolný tvar. Definice typu by tedy mohla vypadat nějak takto:
declare namespace React {
class Component {
props: any;
state: any;
}
}
Všimněte si, že toto je značně zjednodušený příklad pro ilustrativní účely. Koneckonců, tento příspěvek není o Reactu, ale o parametrech generického typu a jejich výchozích hodnotách. Definice typu React v reálném světě na RozhodněTyped jsou mnohem více zapojeny.
Nyní dostáváme návrhy pro kontrolu typu a automatické dokončování:
class Greeting extends React.Component {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Můžeme vytvořit instanci naší komponenty takto:
<Greeting name="World" />
Vykreslení naší komponenty poskytne následující HTML, jak bychom očekávali:
<span>Hello, World!</span>
Zatím je to dobré!
#Použití obecných typů pro rekvizity a stav
Zatímco výše uvedený příklad se zkompiluje a běží v pořádku, naše Component
definice typu je nepřesnější, než bychom chtěli. Protože jsme zadali props
a state
být typu any
, kompilátor TypeScript nám moc nepomůže.
Buďme trochu konkrétnější a představíme dva obecné typy Props
a State
abychom mohli přesně popsat, jaký tvar má props
a state
vlastnosti mají:
declare namespace React {
class Component<Props, State> {
props: Props;
state: State;
}
}
Nyní vytvoříme GreetingProps
typ, který definuje jedinou vlastnost s názvem name
typu string
a předejte jej jako argument typu pro Props
zadejte parametr:
type GreetingProps = { name: string };
class Greeting extends React.Component<GreetingProps, any> {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Nějaká terminologie:
GreetingProps
je argument typu pro parametr typuProps
- Podobně
any
je argument typu pro parametr typuState
Díky těmto typům nyní v rámci naší komponenty získáváme lepší kontrolu typů a návrhy automatického doplňování:
Nyní však musíme poskytněte dva typy, kdykoli rozšíříme React.Component
třída. Náš počáteční příklad kódu již správně nekontroluje typ:
// Error: Generic type 'Component<Props, State>'
// requires 2 type argument(s).
class Greeting extends React.Component {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Pokud nechceme zadat typ jako GreetingProps
, můžeme opravit náš kód poskytnutím any
typ (nebo jiný fiktivní typ, například {}
) pro oba Props
a State
zadejte parametr:
class Greeting extends React.Component<any, any> {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Tento přístup funguje a dělá kontrolu typu šťastným, ale:Nebylo by hezké, kdyby any
byly v tomto případě standardně předpokládané, takže jsme mohli jednoduše vynechat argumenty typu? Zadejte výchozí výchozí hodnoty obecných parametrů.
#Definice obecného typu s výchozím nastavením parametrů typu
Počínaje TypeScriptem 2.3 můžeme volitelně přidat výchozí typ ke každému z našich obecných parametrů typu. V našem případě nám to umožňuje zadat, že obě Props
a State
by měl být any
zadejte, pokud není výslovně uveden argument typu:
declare namespace React {
class Component<Props = any, State = any> {
props: Props;
state: State;
}
}
Nyní náš počáteční příklad kódu kontroluje typ a znovu úspěšně kompiluje s oběma Props
a State
zadejte jako any
:
class Greeting extends React.Component {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Samozřejmě stále můžeme explicitně poskytnout typ pro Props
zadejte parametr a přepište výchozí any
zadejte, stejně jako jsme to dělali dříve:
type GreetingProps = { name: string };
class Greeting extends React.Component<GreetingProps, any> {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Můžeme dělat i jiné zajímavé věci. Oba parametry typu mají nyní výchozí typ, díky čemuž jsou volitelné — nemusíme je poskytovat! To nám umožňuje zadat explicitní argument typu pro Props
zatímco implicitně klesá zpět na any
pro State
typ:
type GreetingProps = { name: string };
class Greeting extends React.Component<GreetingProps> {
render() {
return <span>Hello, {this.props.name}!</span>;
}
}
Všimněte si, že poskytujeme pouze jeden typ argumentu. Můžeme však vynechat pouze volitelné argumenty typu zprava. To znamená, že v tomto případě není možné zadat argument typu pro State
při přechodu zpět na výchozí Props
typ. Podobně při definování typu nesmí za volitelnými parametry typu následovat požadované parametry typu.
#Další příklad
V mém předchozím příspěvku o třídách mixin v TypeScript 2.2 jsem původně deklaroval následující dva aliasy typu:
type Constructor<T> = new (...args: any[]) => T;
type Constructable = Constructor<{}>;
Constructable
typu je čistě syntaktický cukr. Lze jej použít místo Constructor<{}>
typu, abychom nemuseli pokaždé vypisovat argument generického typu. S obecnými výchozími parametry bychom se mohli zbavit dalšího Constructable
zadejte dohromady a vytvořte {}
výchozí typ:
type Constructor<T = {}> = new (...args: any[]) => T;
Syntaxe je o něco složitější, ale výsledný kód je čistší. Pěkné!