Skip to content

Commit dd36e01

Browse files
committed
Add test case motivating prior commit
1 parent 917b904 commit dd36e01

File tree

4 files changed

+877
-0
lines changed

4 files changed

+877
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//// [tests/cases/compiler/propTypeValidatorInference.ts] ////
2+
3+
//// [index.d.ts]
4+
export const nominalTypeHack: unique symbol;
5+
6+
export type IsOptional<T> = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false;
7+
8+
export type RequiredKeys<V> = { [K in keyof V]-?: Exclude<V[K], undefined> extends Validator<infer T> ? IsOptional<T> extends true ? never : K : never }[keyof V];
9+
export type OptionalKeys<V> = Exclude<keyof V, RequiredKeys<V>>;
10+
export type InferPropsInner<V> = { [K in keyof V]-?: InferType<V[K]>; };
11+
12+
export interface Validator<T> {
13+
(props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null;
14+
[nominalTypeHack]?: T;
15+
}
16+
17+
export interface Requireable<T> extends Validator<T | undefined | null> {
18+
isRequired: Validator<NonNullable<T>>;
19+
}
20+
21+
export type ValidationMap<T> = { [K in keyof T]?: Validator<T[K]> };
22+
23+
export type InferType<V> = V extends Validator<infer T> ? T : any;
24+
export type InferProps<V> =
25+
& InferPropsInner<Pick<V, RequiredKeys<V>>>
26+
& Partial<InferPropsInner<Pick<V, OptionalKeys<V>>>>;
27+
28+
export const any: Requireable<any>;
29+
export const array: Requireable<any[]>;
30+
export const bool: Requireable<boolean>;
31+
export const string: Requireable<string>;
32+
export const number: Requireable<number>;
33+
export function shape<P extends ValidationMap<any>>(type: P): Requireable<InferProps<P>>;
34+
export function oneOfType<T extends Validator<any>>(types: T[]): Requireable<NonNullable<InferType<T>>>;
35+
36+
37+
//// [file.ts]
38+
import * as PropTypes from "prop-types";
39+
interface Props {
40+
any?: any;
41+
array: string[];
42+
bool: boolean;
43+
shape: {
44+
foo: string;
45+
bar?: boolean;
46+
baz?: any
47+
};
48+
oneOfType: string | boolean | {
49+
foo?: string;
50+
bar: number;
51+
};
52+
}
53+
54+
type PropTypesMap = PropTypes.ValidationMap<Props>;
55+
56+
const innerProps = {
57+
foo: PropTypes.string.isRequired,
58+
bar: PropTypes.bool,
59+
baz: PropTypes.any
60+
};
61+
62+
const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({
63+
foo: PropTypes.string,
64+
bar: PropTypes.number.isRequired
65+
})];
66+
67+
// TS checking
68+
const propTypes: PropTypesMap = {
69+
any: PropTypes.any,
70+
array: PropTypes.array.isRequired,
71+
bool: PropTypes.bool.isRequired,
72+
shape: PropTypes.shape(innerProps).isRequired,
73+
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,
74+
};
75+
76+
// JS checking
77+
const propTypesWithoutAnnotation = {
78+
any: PropTypes.any,
79+
array: PropTypes.array.isRequired,
80+
bool: PropTypes.bool.isRequired,
81+
shape: PropTypes.shape(innerProps).isRequired,
82+
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired,
83+
};
84+
85+
type ExtractedProps = PropTypes.InferProps<typeof propTypes>;
86+
87+
type ExtractedPropsWithoutAnnotation = PropTypes.InferProps<typeof propTypesWithoutAnnotation>;
88+
89+
type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false;
90+
const x: true = (null as any as ExtractPropsMatch);
91+
92+
//// [file.js]
93+
"use strict";
94+
exports.__esModule = true;
95+
var PropTypes = require("prop-types");
96+
var innerProps = {
97+
foo: PropTypes.string.isRequired,
98+
bar: PropTypes.bool,
99+
baz: PropTypes.any
100+
};
101+
var arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({
102+
foo: PropTypes.string,
103+
bar: PropTypes.number.isRequired
104+
})];
105+
// TS checking
106+
var propTypes = {
107+
any: PropTypes.any,
108+
array: PropTypes.array.isRequired,
109+
bool: PropTypes.bool.isRequired,
110+
shape: PropTypes.shape(innerProps).isRequired,
111+
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired
112+
};
113+
// JS checking
114+
var propTypesWithoutAnnotation = {
115+
any: PropTypes.any,
116+
array: PropTypes.array.isRequired,
117+
bool: PropTypes.bool.isRequired,
118+
shape: PropTypes.shape(innerProps).isRequired,
119+
oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired
120+
};
121+
var x = null;

0 commit comments

Comments
 (0)