diff --git a/types/material-ui-pagination/index.d.ts b/types/material-ui-pagination/index.d.ts index 3e76401f43..1b91e0db3d 100644 --- a/types/material-ui-pagination/index.d.ts +++ b/types/material-ui-pagination/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/lo-tp/material-ui-pagination // Definitions by: m0a // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import * as React from 'react'; export interface PaginationProps { total: number; diff --git a/types/material-ui/index.d.ts b/types/material-ui/index.d.ts index 649a058156..285d949d70 100644 --- a/types/material-ui/index.d.ts +++ b/types/material-ui/index.d.ts @@ -14,7 +14,7 @@ // Sam Walsh // Tim de Koning // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 /// /// diff --git a/types/ngreact/index.d.ts b/types/ngreact/index.d.ts index 6db92506ce..1f4a31b6be 100644 --- a/types/ngreact/index.d.ts +++ b/types/ngreact/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/ngReact/ngReact // Definitions by: Vicky Lai // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 /// /// diff --git a/types/prop-types/index.d.ts b/types/prop-types/index.d.ts index 67146e6cc7..33ff7ae783 100644 --- a/types/prop-types/index.d.ts +++ b/types/prop-types/index.d.ts @@ -1,33 +1,52 @@ // Type definitions for prop-types 15.5 // Project: https://github.com/reactjs/prop-types // Definitions by: DovydasNavickas +// Ferdy Budhidharma // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.2 +// TypeScript Version: 2.8 -export type Validator = (object: T, key: string, componentName: string, ...rest: any[]) => Error | null; +import { ReactNode, ReactElement } from 'react'; -export interface Requireable extends Validator { - isRequired: Validator; +export const nominalTypeHack: unique symbol; + +export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; + +export type RequiredKeys = { [K in keyof V]: V[K] extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; +export type OptionalKeys = Exclude>; +export type InferPropsInner = { [K in keyof V]: InferType; }; + +export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; + [nominalTypeHack]?: T; } -export type ValidationMap = {[K in keyof T]?: Validator }; +export interface Requireable extends Validator { + isRequired: Validator>; +} + +export type ValidationMap = { [K in keyof T]-?: Validator }; + +export type InferType = V extends Validator ? T : any; +export type InferProps = + & InferPropsInner>> + & Partial>>>; export const any: Requireable; -export const array: Requireable; -export const bool: Requireable; -export const func: Requireable; -export const number: Requireable; -export const object: Requireable; -export const string: Requireable; -export const node: Requireable; -export const element: Requireable; -export const symbol: Requireable; -export function instanceOf(expectedClass: {}): Requireable; -export function oneOf(types: any[]): Requireable; -export function oneOfType(types: Array>): Requireable; -export function arrayOf(type: Validator): Requireable; -export function objectOf(type: Validator): Requireable; -export function shape(type: ValidationMap): Requireable; +export const array: Requireable; +export const bool: Requireable; +export const func: Requireable<(...args: any[]) => any>; +export const number: Requireable; +export const object: Requireable; +export const string: Requireable; +export const node: Requireable; +export const element: Requireable>; +export const symbol: Requireable; +export function instanceOf(expectedClass: new (...args: any[]) => T): Requireable; +export function oneOf(types: T[]): Requireable; +export function oneOfType>(types: T[]): Requireable>>; +export function arrayOf(type: Validator): Requireable; +export function objectOf(type: Validator): Requireable<{ [K in keyof any]: T; }>; +export function shape

>(type: P): Requireable>; /** * Assert that the values match with the type specs. diff --git a/types/prop-types/prop-types-tests.ts b/types/prop-types/prop-types-tests.ts index 4d5a939b6e..a9bde3af00 100644 --- a/types/prop-types/prop-types-tests.ts +++ b/types/prop-types/prop-types-tests.ts @@ -1,29 +1,207 @@ +import { ReactElement, ReactNode } from "react"; import * as PropTypes from "prop-types"; +declare const uniqueType: unique symbol; + +class TestClass { } + interface Props { - any: any; + any?: any; array: string[]; bool: boolean; - func: any; - string: string; + element: ReactElement; + func(foo: string): void; + node?: ReactNode; + requiredNode: NonNullable; number: number; + object: object; + string: string; symbol: symbol; - object: {}; - node: any; - element: any; + instanceOf: TestClass; + oneOf: 'a' | 'b' | 'c'; + oneOfType: string | boolean | { + foo?: string; + bar: number; + }; + numberOrFalse: false | number; + nodeOrRenderFn?: ReactNode | (() => ReactNode); + arrayOf: boolean[]; + objectOf: { [K: string]: number }; + shape: { + foo: string; + bar?: boolean; + baz?: any + }; + optionalNumber?: number | null; + customProp?: typeof uniqueType; } -const propTypes: PropTypes.ValidationMap = { - any: PropTypes.any.isRequired, +const innerProps = { + foo: PropTypes.string.isRequired, + bar: PropTypes.bool, + baz: PropTypes.any +}; + +const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ + foo: PropTypes.string, + bar: PropTypes.number.isRequired +})]; +type PropTypesMap = PropTypes.ValidationMap; + +// TS checking +const propTypes: PropTypesMap = { + any: PropTypes.any, array: PropTypes.array.isRequired, bool: PropTypes.bool.isRequired, + element: PropTypes.element.isRequired, func: PropTypes.func.isRequired, + node: PropTypes.node, + requiredNode: PropTypes.node.isRequired, number: PropTypes.number.isRequired, object: PropTypes.object.isRequired, string: PropTypes.string.isRequired, symbol: PropTypes.symbol.isRequired, - node: PropTypes.node.isRequired, - element: PropTypes.element.isRequired + instanceOf: PropTypes.instanceOf(TestClass).isRequired, + oneOf: PropTypes.oneOf<'a' | 'b' | 'c'>(['a', 'b', 'c']).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, + numberOrFalse: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.number]).isRequired, + // The generic function type (() => any) is assignable to ReactNode because ReactNode extends the empty object type {} + // Which widens the array literal of validators to just Array any>> + // It's too risky to change ReactNode to exclude {} even though it's invalid, as it's required for children-as-function props to work + // So we assert the explicit tuple type + nodeOrRenderFn: PropTypes.oneOfType([PropTypes.node, PropTypes.func] as [PropTypes.Requireable, PropTypes.Requireable<() => any>]), + arrayOf: PropTypes.arrayOf(PropTypes.bool.isRequired).isRequired, + objectOf: PropTypes.objectOf(PropTypes.number.isRequired).isRequired, + shape: PropTypes.shape(innerProps).isRequired, + optionalNumber: PropTypes.number, + customProp: (() => null) as PropTypes.Validator }; -PropTypes.checkPropTypes({xs: PropTypes.array}, {xs: []}, 'location', 'componentName'); +// JS checking +const propTypesWithoutAnnotation = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + element: PropTypes.element.isRequired, + func: PropTypes.func.isRequired, + node: PropTypes.node, + requiredNode: PropTypes.node.isRequired, + number: PropTypes.number.isRequired, + object: PropTypes.object.isRequired, + string: PropTypes.string.isRequired, + symbol: PropTypes.symbol.isRequired, + instanceOf: PropTypes.instanceOf(TestClass).isRequired, + // required generic specification because of array type widening + oneOf: PropTypes.oneOf<'a' | 'b' | 'c'>(['a', 'b', 'c']).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, + numberOrFalse: PropTypes.oneOfType([PropTypes.oneOf([false]), PropTypes.number]).isRequired, + nodeOrRenderFn: PropTypes.oneOfType([PropTypes.node, PropTypes.func] as [PropTypes.Requireable, PropTypes.Requireable<() => any>]), + arrayOf: PropTypes.arrayOf(PropTypes.bool.isRequired).isRequired, + objectOf: PropTypes.objectOf(PropTypes.number.isRequired).isRequired, + shape: PropTypes.shape(innerProps).isRequired, + optionalNumber: PropTypes.number, + customProp: (() => null) as PropTypes.Validator +}; + +const partialPropTypes = { + number: PropTypes.number.isRequired, + object: PropTypes.object.isRequired, + string: PropTypes.string.isRequired, + symbol: PropTypes.symbol.isRequired, +}; + +const outerPropTypes = { + props: PropTypes.shape(propTypes).isRequired +}; + +const outerPropTypesWithoutAnnotation = { + props: PropTypes.shape(propTypesWithoutAnnotation).isRequired +}; + +type ExtractedArrayProps = PropTypes.InferType<(typeof arrayOfTypes)[number]>; + +type ExtractedInnerProps = PropTypes.InferProps; + +type ExtractedProps = PropTypes.InferProps; +type ExtractedPropsFromOuterProps = PropTypes.InferProps['props']; +type ExtractedPartialProps = PropTypes.InferProps; + +type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; +type ExtractedPropsFromOuterPropsWithoutAnnotation = PropTypes.InferProps['props']; + +// $ExpectType: true +type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; +// $ExpectType: true +type ExtractPropsMatch2 = ExtractedPropsWithoutAnnotation extends ExtractedProps ? true : false; +// $ExpectType: true +type ExtractPropsMatch3 = ExtractedProps extends Props ? true : false; +// $ExpectType: true +type ExtractPropsMatch4 = Props extends ExtractedPropsWithoutAnnotation ? true : false; +// $ExpectType: true +type ExtractFromOuterPropsMatch = ExtractedPropsFromOuterProps extends ExtractedPropsFromOuterPropsWithoutAnnotation ? true : false; +// $ExpectType: true +type ExtractFromOuterPropsMatch2 = ExtractedPropsFromOuterPropsWithoutAnnotation extends ExtractedPropsFromOuterProps ? true : false; +// $ExpectType: true +type ExtractFromOuterPropsMatch3 = ExtractedPropsFromOuterProps extends Props ? true : false; +// $ExpectType: true +type ExtractFromOuterPropsMatch4 = Props extends ExtractedPropsFromOuterPropsWithoutAnnotation ? true : false; + +// $ExpectType: false +type ExtractPropsMismatch = ExtractedPartialProps extends Props ? true : false; + +// $ExpectType: {} +type UnmatchedPropKeys = Pick>; +// $ExpectType: {} +type UnmatchedPropKeys2 = Pick>; + +PropTypes.checkPropTypes({ xs: PropTypes.array }, { xs: [] }, 'location', 'componentName'); + +// This would be the type that JSX sees +type Defaultize = + & Pick> + & Partial>> + & Partial>>; + +// This would be the type inside the component +type Undefaultize = + & Pick> + & { [K in Extract]-?: Exclude; } + & Required>>; + +const componentPropTypes = { + fi: PropTypes.func.isRequired, + foo: PropTypes.string, + bar: PropTypes.number.isRequired, + baz: PropTypes.bool, + bat: PropTypes.node +}; + +const componentDefaultProps = { + fi: () => null, + baz: false, + bat: ['This', 'is', 'a', 'string'] +}; + +type DefaultizedProps = Defaultize, typeof componentDefaultProps>; +type UndefaultizedProps = Undefaultize, typeof componentDefaultProps>; + +// $ExpectType: true +type DefaultizedPropsTest = { + fi?: (...args: any[]) => any; + foo?: string | null; + bar: number; + baz?: boolean | null; + bat?: ReactNode; +} extends DefaultizedProps ? true : false; +// $ExpectType: true +type UndefaultizedPropsTest = { + fi: (...args: any[]) => any; + foo?: string | null; + bar: number; + baz: boolean; + bat: Exclude; +} extends UndefaultizedProps ? true : false; diff --git a/types/react-foundation/index.d.ts b/types/react-foundation/index.d.ts index 9c88ff2f7e..51433b1fd9 100644 --- a/types/react-foundation/index.d.ts +++ b/types/react-foundation/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/digiaonline/react-foundation // Definitions by: Daniel Earwicker // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 export { Accordion, AccordionItem, AccordionTitle, AccordionContent } from './components/accordion'; export { Badge } from './components/badge'; diff --git a/types/react-is-deprecated/index.d.ts b/types/react-is-deprecated/index.d.ts index 791cb97862..d5d3927177 100644 --- a/types/react-is-deprecated/index.d.ts +++ b/types/react-is-deprecated/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/Aweary/react-is-deprecated // Definitions by: Sean Kelley // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 declare module 'react-is-deprecated' { import { Validator, Requireable, ValidationMap, ReactPropTypes } from 'react'; diff --git a/types/react-leaflet/index.d.ts b/types/react-leaflet/index.d.ts index 48a98bfbca..c362a1f23c 100644 --- a/types/react-leaflet/index.d.ts +++ b/types/react-leaflet/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/PaulLeCam/react-leaflet // Definitions by: Dave Leaver , David Schneider , Yui T. // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import * as Leaflet from 'leaflet'; import * as React from 'react'; diff --git a/types/react-props-decorators/index.d.ts b/types/react-props-decorators/index.d.ts index 8aa59e5194..5396fa81ca 100644 --- a/types/react-props-decorators/index.d.ts +++ b/types/react-props-decorators/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/popkirby/react-props-decorators // Definitions by: Qubo // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 /// diff --git a/types/react-sortable-tree/index.d.ts b/types/react-sortable-tree/index.d.ts index 498fd48800..0415db0414 100644 --- a/types/react-sortable-tree/index.d.ts +++ b/types/react-sortable-tree/index.d.ts @@ -4,7 +4,7 @@ // Jovica Zoric // Kevin Perrine // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import * as React from 'react'; import { ListProps, Index } from 'react-virtualized'; diff --git a/types/react-virtualized-select/index.d.ts b/types/react-virtualized-select/index.d.ts index 83c062eab7..402b027785 100644 --- a/types/react-virtualized-select/index.d.ts +++ b/types/react-virtualized-select/index.d.ts @@ -2,7 +2,7 @@ // Project: https://github.com/bvaughn/react-virtualized-select // Definitions by: Sean Kelley // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import * as React from "react"; import { ReactSelectProps, ReactAsyncSelectProps, ReactCreatableSelectProps, LoadOptionsHandler, OptionValues } from "react-select"; diff --git a/types/react-virtualized/index.d.ts b/types/react-virtualized/index.d.ts index 2714e9a93c..b7c557d875 100644 --- a/types/react-virtualized/index.d.ts +++ b/types/react-virtualized/index.d.ts @@ -8,7 +8,7 @@ // Steve Zhang // Maciej Goszczycki // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 export { ArrowKeyStepper, diff --git a/types/react/test/index.ts b/types/react/test/index.ts index 3b7e5193fd..227ba5721d 100644 --- a/types/react/test/index.ts +++ b/types/react/test/index.ts @@ -11,7 +11,6 @@ import * as TestUtils from "react-addons-test-utils"; import TransitionGroup = require("react-addons-transition-group"); import update = require("react-addons-update"); import createReactClass = require("create-react-class"); -import * as PropTypes from "prop-types"; import * as DOM from "react-dom-factories"; interface Props extends React.Attributes { @@ -91,10 +90,10 @@ declare const container: Element; }; // Even if state is not set, this is allowed by React - this.setState({inputValue: 'hello'}); + this.setState({ inputValue: 'hello' }); this.setState((prevState, props) => { // $ExpectError - props = {foo: 'nope'}; + props = { foo: 'nope' }; // $ExpectError props.foo = 'nope'; @@ -118,15 +117,15 @@ declare const container: Element; class ModernComponent extends React.Component implements MyComponent, React.ChildContextProvider { static propTypes: React.ValidationMap = { - foo: PropTypes.number + foo: (() => null) as React.Validator }; static contextTypes: React.ValidationMap = { - someValue: PropTypes.string + someValue: (() => null) as React.Validator }; static childContextTypes: React.ValidationMap = { - someOtherValue: PropTypes.string + someOtherValue: (() => null) as React.Validator }; context: Context; @@ -180,7 +179,7 @@ class ModernComponent extends React.Component class ModernComponentArrayRender extends React.Component { render() { return [DOM.h1({ key: "1" }, "1"), - DOM.h1({ key: "2" }, "2")]; + DOM.h1({ key: "2" }, "2")]; } } @@ -436,99 +435,6 @@ DOM.svg({ }) ); -// -// PropTypes -// -------------------------------------------------------------------------- - -const PropTypesSpecification: React.ComponentSpec = { - propTypes: { - optionalArray: PropTypes.array, - optionalBool: PropTypes.bool, - optionalFunc: PropTypes.func, - optionalNumber: PropTypes.number, - optionalObject: PropTypes.object, - optionalString: PropTypes.string, - optionalNode: PropTypes.node, - optionalElement: PropTypes.element, - optionalMessage: PropTypes.instanceOf(Date), - optionalEnum: PropTypes.oneOf(["News", "Photos"]), - optionalUnion: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - PropTypes.instanceOf(Date) - ]), - optionalArrayOf: PropTypes.arrayOf(PropTypes.number), - optionalObjectOf: PropTypes.objectOf(PropTypes.number), - optionalObjectWithShape: PropTypes.shape({ - color: PropTypes.string, - fontSize: PropTypes.number - }), - requiredFunc: PropTypes.func.isRequired, - requiredAny: PropTypes.any.isRequired, - customProp(props: any, propName: string, componentName: string): Error | null { - if (!/matchme/.test(props[propName])) { - return new Error("Validation failed!"); - } - return null; - }, - // https://facebook.github.io/react/warnings/dont-call-proptypes.html#fixing-the-false-positive-in-third-party-proptypes - percentage: (object: any, key: string, componentName: string, ...rest: any[]): Error | null => { - const error = PropTypes.number(object, key, componentName, ...rest); - if (error) { - return error; - } - if (object[key] < 0 || object[key] > 100) { - return new Error(`prop ${key} must be between 0 and 100`); - } - return null; - } - }, - render: (): React.ReactElement | null => { - return null; - } -}; - -// -// ContextTypes -// -------------------------------------------------------------------------- - -const ContextTypesSpecification: React.ComponentSpec = { - contextTypes: { - optionalArray: PropTypes.array, - optionalBool: PropTypes.bool, - optionalFunc: PropTypes.func, - optionalNumber: PropTypes.number, - optionalObject: PropTypes.object, - optionalString: PropTypes.string, - optionalNode: PropTypes.node, - optionalElement: PropTypes.element, - optionalMessage: PropTypes.instanceOf(Date), - optionalEnum: PropTypes.oneOf(["News", "Photos"]), - optionalUnion: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number, - PropTypes.instanceOf(Date) - ]), - optionalArrayOf: PropTypes.arrayOf(PropTypes.number), - optionalObjectOf: PropTypes.objectOf(PropTypes.number), - optionalObjectWithShape: PropTypes.shape({ - color: PropTypes.string, - fontSize: PropTypes.number - }), - requiredFunc: PropTypes.func.isRequired, - requiredAny: PropTypes.any.isRequired, - customProp(props: any, propName: string, componentName: string): Error | null { - if (!/matchme/.test(props[propName])) { - return new Error("Validation failed!"); - } - return null; - } - }, - render: (): null => { - return null; - } -}; - // // React.Children // -------------------------------------------------------------------------- diff --git a/types/redux-form/index.d.ts b/types/redux-form/index.d.ts index 5ff24c90a0..989d9222d0 100644 --- a/types/redux-form/index.d.ts +++ b/types/redux-form/index.d.ts @@ -10,7 +10,7 @@ // Tim de Koning // Maddi Joyce // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import { ComponentClass, StatelessComponent, diff --git a/types/redux-form/v4/index.d.ts b/types/redux-form/v4/index.d.ts index 3ecd2d87cc..4e21aee1fa 100644 --- a/types/redux-form/v4/index.d.ts +++ b/types/redux-form/v4/index.d.ts @@ -2,12 +2,12 @@ // Project: https://github.com/erikras/redux-form // Definitions by: Daniel Lytkin // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.6 +// TypeScript Version: 2.8 import * as React from 'react'; import { Dispatch, ActionCreator, Reducer } from 'redux'; -export const actionTypes: {[actionName: string]: string}; +export const actionTypes: { [actionName: string]: string }; export type FieldValue = any; @@ -464,7 +464,7 @@ export declare const reducer: { [formName: string]: { [fieldName: string]: Normalizer } - }): Reducer; + }): Reducer; /** * Returns a form reducer that will also pass each action through @@ -473,5 +473,5 @@ export declare const reducer: { * passed to each reducer will only be the slice that pertains to that * form. */ - plugin(reducers: { [formName: string]: Reducer }): Reducer; + plugin(reducers: { [formName: string]: Reducer }): Reducer; };