Created
March 28, 2018 13:57
-
-
Save andyedinborough/cf1dca5844e86620d183e09dea47d125 to your computer and use it in GitHub Desktop.
Demo of conditional types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
type Parse<T> = { parse: (value: string) => T }; | |
type MaybeParse<T> = T extends string ? {} : Parse<T>; | |
interface GenericTextboxBaseProps<TModel, TProperties extends keyof TModel> { | |
model: TModel; | |
name: TProperties; | |
display?: (prop: TModel[TProperties]) => string; | |
} | |
type GenericTextboxProps<TModel, TProperties extends keyof TModel, TProperty extends TModel[TProperties]> = | |
GenericTextboxBaseProps<TModel, TProperties> & MaybeParse<TProperty>; | |
interface GenericTextboxState { | |
} | |
export class GenericTextbox< | |
TModel, | |
TProperties extends keyof TModel, | |
TProperty extends TModel[TProperties] | |
> extends React.Component<GenericTextboxProps<TModel, TProperties, TProperty>, GenericTextboxState> { | |
render () { | |
const { model, name, display } = this.props; | |
return ( | |
<input | |
name={name} | |
value={display ? display(model[name]) : String(model[name] || '')} | |
onChange={this.handleChange} | |
/> | |
); | |
} | |
private handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
const { value } = e.currentTarget; | |
const { model, name } = this.props; | |
const { parse } = this.props as GenericTextboxProps<TModel, TProperties, TProperty> as Parse<TProperty>; | |
if (parse) { | |
model[name] = parse(value); | |
} else { | |
model[name as string] = value; | |
} | |
}; | |
} | |
interface Person { | |
name: string; | |
age: number; | |
} | |
const person: Person = { name: 'Steve', age: 34 }; | |
export const test = () => ( | |
<> | |
<GenericTextbox model={person} name="name" /> | |
<GenericTextbox model={person} name="age" parse={(v: string) => parseInt(v, 10) || 0} /> | |
{/* | |
error: dne doesn't exist in person | |
<GenericTextbox model={person} name="dne" /> | |
error: parse prop missing | |
<GenericTextbox model={person} name="age" /> | |
error: parse return type doesn't match person.age | |
<GenericTextbox model={person} name="age" parse={v => new Date()} /> | |
*/} | |
</> | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment