Skip to content

Commit

Permalink
Merge pull request #1181 from Alexendoo/typed-defaultProps
Browse files Browse the repository at this point in the history
Enable Typescript to understand JSX default props
  • Loading branch information
marvinhagemeister committed Sep 10, 2018
2 parents 62c04e0 + d1974c7 commit b5c4a36
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -119,7 +119,7 @@
"rollup-plugin-node-resolve": "^3.0.0",
"sinon": "^4.4.2",
"sinon-chai": "^3.0.0",
"typescript": "^2.9.0-rc",
"typescript": "^3.0.1",
"uglify-js": "^2.7.5",
"webpack": "^4.3.0"
},
Expand Down
14 changes: 14 additions & 0 deletions src/preact.d.ts
Expand Up @@ -124,6 +124,15 @@ declare namespace preact {
};
}

type Defaultize<Props, Defaults> =
// Distribute over unions
Props extends any
? // Make any properties included in Default optional
& Partial<Pick<Props, Extract<keyof Props, keyof Defaults>>>
// Include the remaining properties from Props
& Pick<Props, Exclude<keyof Props, keyof Defaults>>
: never;

declare global {
namespace JSX {
interface Element extends preact.VNode<any> {
Expand All @@ -140,6 +149,11 @@ declare global {
children: any;
}

type LibraryManagedAttributes<Component, Props> =
Component extends { defaultProps: infer Defaults }
? Defaultize<Props, Defaults>
: Props;

interface SVGAttributes extends HTMLAttributes {
accentHeight?: number | string;
accumulate?: "none" | "sum";
Expand Down
65 changes: 65 additions & 0 deletions test/ts/preact.tsx
Expand Up @@ -125,3 +125,68 @@ class ComponentWithLifecycle extends Component<DummyProps, DummyState> {
console.log("componentDidUpdate", previousProps, previousState, previousContext);
}
}

// Default props: JSX.LibraryManagedAttributes

class DefaultProps extends Component<{text: string, bool: boolean}> {
static defaultProps = {
text: "hello"
};

render() {
return <div>{this.props.text}</div>;
}
}

const d1 = <DefaultProps bool={false} text="foo" />;
const d2 = <DefaultProps bool={false} />;

class DefaultPropsWithUnion extends Component<
{ default: boolean } & (
| {
type: "string";
str: string;
}
| {
type: "number";
num: number;
})
> {
static defaultProps = {
default: true
};

render() {
return <div />;
}
}

const d3 = <DefaultPropsWithUnion type="string" str={"foo"} />;
const d4 = <DefaultPropsWithUnion type="number" num={0xf00} />;
const d5 = <DefaultPropsWithUnion type="string" str={"foo"} default={false} />;
const d6 = <DefaultPropsWithUnion type="number" num={0xf00} default={false} />;

class DefaultUnion extends Component<
| {
type: "number";
num: number;
}
| {
type: "string";
str: string;
}
> {
static defaultProps = {
type: "number",
num: 1
};

render() {
return <div />;
}
}

const d7 = <DefaultUnion />;
const d8 = <DefaultUnion num={1} />;
const d9 = <DefaultUnion type="number" />;
const d10 = <DefaultUnion type="string" str="foo" />;

0 comments on commit b5c4a36

Please sign in to comment.