diff --git a/.prettierrc b/.prettierrc index eca9e731..2d8ad382 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,17 @@ -semi: false -singleQuote: true -trailingComma: none +{ + "semi": false, + "singleQuote": true, + "trailingComma": "none", + "overrides": [ + { + "files": [".prettierrc"], + "options": { "parser": "json" } + }, + { + "files": ["*.ts*"], + "options": { + "semi": true + } + } + ] +} diff --git a/package-scripts.js b/package-scripts.js index 00cebfb4..24b2be87 100644 --- a/package-scripts.js +++ b/package-scripts.js @@ -52,7 +52,7 @@ module.exports = { andTest: series.nps('build', 'test.size') }, copyTypes: series( - npsUtils.copy('src/*.js.flow src/*.d.ts dist'), + npsUtils.copy('src/*.js.flow dist'), npsUtils.copy( 'dist/index.js.flow dist --rename="react-final-form.cjs.js.flow"' ), @@ -73,8 +73,10 @@ module.exports = { script: 'flow check' }, typescript: { - description: 'typescript check the entire project', - script: 'tsc' + default: { + description: 'typescript', + script: 'dtslint --onlyTestTsNext ./typescript' + } }, validate: { description: diff --git a/package.json b/package.json index 7a4a62e4..0c369aa7 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "main": "dist/react-final-form.cjs.js", "jsnext:main": "dist/react-final-form.es.js", "module": "dist/react-final-form.es.js", - "typings": "dist/index.d.ts", + "typings": "typescript/index.d.ts", "files": [ "dist", - "scripts" + "scripts", + "typescript" ], "scripts": { "start": "nps", @@ -50,8 +51,9 @@ "babel-jest": "^24.1.0", "bundlesize": "^0.17.1", "doctoc": "^1.4.0", - "eslint": "^5.15.0", - "eslint-config-react-app": "^3.0.7", + "dtslint": "^0.4.4", + "eslint": "^5.13.0", + "eslint-config-react-app": "^3.0.6", "eslint-plugin-babel": "^5.2.1", "eslint-plugin-flowtype": "^3.4.2", "eslint-plugin-import": "^2.16.0", diff --git a/src/index.d.ts b/src/index.d.ts deleted file mode 100644 index ddf7b31c..00000000 --- a/src/index.d.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as React from 'react' -import { - FormApi, - Config, - Decorator, - FormState, - FormSubscription, - FieldState, - FieldSubscription -} from 'final-form' - -export interface ReactContext { - reactFinalForm: FormApi -} - -export type FieldPlaneState = Pick< - FieldState, - Exclude -> - -export interface FieldRenderProps { - input: { - name: string - onBlur: (event?: React.FocusEvent) => void - onChange: (event: React.ChangeEvent | any) => void - onFocus: (event?: React.FocusEvent) => void - value: any - checked?: boolean - } - meta: FieldPlaneState -} - -export interface SubsetFormApi { - batch: (fn: () => void) => void - blur: (name: string) => void - change: (name: string, value: any) => void - focus: (name: string) => void - initialize: (values: object) => void - mutators: { [key: string]: Function } - reset: () => void -} - -export interface FormRenderProps extends FormState, SubsetFormApi { - batch: (fn: () => void) => void - form: FormApi - handleSubmit: ( - event?: React.SyntheticEvent - ) => Promise | undefined -} - -export interface FormSpyRenderProps extends FormState, SubsetFormApi { - form: FormApi -} - -export interface RenderableProps { - children?: ((props: T) => React.ReactNode) | React.ReactNode - component?: React.ComponentType | string - render?: (props: T) => React.ReactNode -} - -export interface FormProps extends Config, RenderableProps { - subscription?: FormSubscription - decorators?: Decorator[] - initialValuesEqual?: (a?: object, b?: object) => boolean -} - -export interface FieldProps extends RenderableProps { - allowNull?: boolean - defaultValue?: any - format?: ((value: any, name: string) => any) | null - formatOnBlur?: boolean - parse?: ((value: any, name: string) => any) | null - name: string - initialValue?: any - isEqual?: (a: any, b: any) => boolean - subscription?: FieldSubscription - validate?: (value: any, allValues: object, meta?: FieldPlaneState) => any - value?: any - [otherProp: string]: any -} - -export interface FormSpyProps extends RenderableProps { - onChange?: (formState: FormState) => void - subscription?: FormSubscription -} - -export var Field: React.ComponentType -export var Form: React.ComponentType -export var FormSpy: React.ComponentType -export var version: string - -export function withReactFinalForm( - component: React.ComponentType -): React.ComponentType - -export var ReactFinalFormContext: React.Context diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 9678d10a..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "lib": ["es2015", "dom"], - "jsx": "react", - "baseUrl": ".", - "noEmit": true, - "strict": true - }, - "include": ["./src/**/*"] -} diff --git a/typescript/index.d.ts b/typescript/index.d.ts new file mode 100644 index 00000000..fb4ac35d --- /dev/null +++ b/typescript/index.d.ts @@ -0,0 +1,104 @@ +import * as React from 'react'; +import { + FormApi, + Config, + Decorator, + FormState, + FormSubscription, + FieldSubscription +} from 'final-form'; + +export interface ReactContext { + reactFinalForm: FormApi; +} + +export interface FieldRenderProps { + input: { + name: string; + onBlur: (event?: React.FocusEvent) => void; + onChange: (event: React.ChangeEvent) => void; + onFocus: (event?: React.FocusEvent) => void; + value: any; + checked?: boolean; + }; + meta: Partial<{ + // TODO: Make a diff of `FieldState` without all the functions + active: boolean; + data: object; + dirty: boolean; + dirtySinceLastSubmit: boolean; + error: any; + initial: any; + invalid: boolean; + pristine: boolean; + submitError: any; + submitFailed: boolean; + submitSucceeded: boolean; + submitting: boolean; + touched: boolean; + valid: boolean; + visited: boolean; + }>; +} + +export interface SubsetFormApi { + batch: (fn: () => void) => void; + blur: (name: string) => void; + change: (name: string, value: any) => void; + focus: (name: string) => void; + initialize: (values: object) => void; + mutators: { [key: string]: (...args: any[]) => any }; + reset: () => void; +} + +export interface FormRenderProps extends FormState, SubsetFormApi { + batch: (fn: () => void) => void; + form: FormApi; + handleSubmit: ( + event?: React.SyntheticEvent + ) => Promise | undefined; +} + +export interface FormSpyRenderProps extends FormState, SubsetFormApi { + form: FormApi; +} + +export interface RenderableProps { + children?: ((props: T) => React.ReactNode) | React.ReactNode; + component?: React.ComponentType | string; + render?: (props: T) => React.ReactNode; +} + +export interface FormProps extends Config, RenderableProps { + subscription?: FormSubscription; + decorators?: Decorator[]; + initialValuesEqual?: (a?: object, b?: object) => boolean; +} + +export interface FieldProps + extends RenderableProps> { + allowNull?: boolean; + format?: ((value: any, name: string) => any) | null; + formatOnBlur?: boolean; + parse?: ((value: any, name: string) => any) | null; + name: string; + isEqual?: (a: any, b: any) => boolean; + subscription?: FieldSubscription; + validate?: (value: any, allValues: object) => any; + value?: any; + [otherProp: string]: any; +} + +export interface FormSpyProps extends RenderableProps { + onChange?: (formState: FormState) => void; + subscription?: FormSubscription; +} + +export const Field: React.ComponentType>; +export const Form: React.ComponentType; +export const FormSpy: React.ComponentType; +export const version: string; + +export function withReactFinalForm( + component: React.ComponentType +): React.ComponentType; diff --git a/typescript/index.tsx b/typescript/index.tsx new file mode 100644 index 00000000..0f4b2bee --- /dev/null +++ b/typescript/index.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; +import { Form } from 'react-final-form'; + +const noop = () => {}; +// missing required props +const C1 = () => { + // $ExpectError + return
; +}; + +// provided required props +const C2 = () => ; diff --git a/typescript/tsconfig.json b/typescript/tsconfig.json new file mode 100644 index 00000000..d60c7a60 --- /dev/null +++ b/typescript/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2015", "dom"], + "jsx": "react", + "baseUrl": ".", + "noEmit": true, + "strict": true, + "moduleResolution": "node", + "paths": { + "react-final-form": [".."] + } + }, + "include": ["."] +}