From d598a1d498b52d92418343016ae3685339861072 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 16 Dec 2020 16:01:26 +0800 Subject: [PATCH 1/4] fix: fix drawer wrong characters (#28382) --- components/drawer/index.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/drawer/index.zh-CN.md b/components/drawer/index.zh-CN.md index e4fdb889f0..9e6e9dfcf5 100644 --- a/components/drawer/index.zh-CN.md +++ b/components/drawer/index.zh-CN.md @@ -10,7 +10,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg ## 何时使用 -抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到到原任务。 +抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到原任务。 - 当需要一个附加的面板来控制父窗体内容,这个面板在需要时呼出。比如,控制界面展示样式,往界面中添加内容。 - 当需要在当前任务流中插入临时任务,创建或预览附加内容。比如展示协议条款,创建子对象。 From 6f529a49fbe9ad314ce2f11e653a749f502c8e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=81=8F=E5=8F=B3?= Date: Thu, 17 Dec 2020 11:23:24 +0800 Subject: [PATCH 2/4] docs: fix typo (#28396) * Update illustration.zh-CN.md * Update illustration.en-US.md --- docs/spec/illustration.en-US.md | 2 +- docs/spec/illustration.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/spec/illustration.en-US.md b/docs/spec/illustration.en-US.md index b0f1498992..65395483e8 100644 --- a/docs/spec/illustration.en-US.md +++ b/docs/spec/illustration.en-US.md @@ -51,7 +51,7 @@ Through research, we discovered blue and white accounts for a large proportion a -Sea Hare's palette combined with Adobe's ternary color picker and mosaic ball, you can easily obtain the Dedult version of the basic color palette. +Sea Hare's palette combined with Adobe's ternary color picker and mosaic ball, you can easily obtain the default version of the basic color palette.
diff --git a/docs/spec/illustration.zh-CN.md b/docs/spec/illustration.zh-CN.md index 61a4a670ef..4a6ebd7ea4 100644 --- a/docs/spec/illustration.zh-CN.md +++ b/docs/spec/illustration.zh-CN.md @@ -51,7 +51,7 @@ title: -基于 Adobe Color 的三元取色工具,和 3D 立体马赛克球,结合我们自己的海兔色板。可以轻松得到了我们 Dedult 版本的基础色板。 +基于 Adobe Color 的三元取色工具,和 3D 立体马赛克球,结合我们自己的海兔色板。可以轻松得到了我们 Default 版本的基础色板。
From 0a6167b995b67cfc5fba8b30d3c6a59279b43d77 Mon Sep 17 00:00:00 2001 From: Tom Xu Date: Thu, 17 Dec 2020 13:29:15 +0800 Subject: [PATCH 3/4] docs: fix typo (#28397) --- docs/spec/illustration.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/illustration.zh-CN.md b/docs/spec/illustration.zh-CN.md index 4a6ebd7ea4..84c01076ff 100644 --- a/docs/spec/illustration.zh-CN.md +++ b/docs/spec/illustration.zh-CN.md @@ -51,7 +51,7 @@ title: -基于 Adobe Color 的三元取色工具,和 3D 立体马赛克球,结合我们自己的海兔色板。可以轻松得到了我们 Default 版本的基础色板。 +基于 Adobe Color 的三元取色工具,和 3D 立体马赛克球,结合我们自己的海兔色板。可以轻松得到了我们默认版本的基础色板。
From 55e0d13234bbb750b5b978b19bea316831a5d69e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Thu, 17 Dec 2020 15:09:18 +0800 Subject: [PATCH 4/4] chore: Add demo tsx check (#28389) * chore: Add demo tsx check * chore: Prettier * chore: Fix lint * fix: Upload ts definition * chore: Demo onlt * docs: Fix demo * chore: Add CI action * chore: Use real name * chore: fix ts define * chore: fix more ts * chore: fix more ts * chore: More ts * chore: More ts * chore: More ts * chore: More ts * chore: More ts * chore: More ts * chore: More ts * chore: Update all rest TS demo * fix test case --- .eslintignore | 3 +- .github/workflows/test.yml | 22 +++++ components/affix/demo/target.md | 2 +- .../__tests__/__snapshots__/demo.test.ts.snap | 2 +- components/alert/demo/error-boundary.md | 2 +- .../auto-complete/demo/non-case-sensitive.md | 2 +- .../auto-complete/demo/uncertain-category.md | 2 +- components/drawer/demo/config-provider.md | 4 +- components/form/demo/advanced-search.md | 2 +- components/form/demo/basic.md | 4 +- components/form/demo/control-hooks.md | 4 +- components/form/demo/control-ref.md | 14 +-- .../form/demo/customized-form-controls.md | 18 ++-- components/form/demo/dynamic-rule.md | 2 +- components/form/demo/form-context.md | 14 ++- components/form/demo/form-in-modal.md | 2 +- components/form/demo/global-state.md | 14 +-- components/form/demo/inline-login.md | 6 +- components/form/demo/layout.md | 6 +- components/form/demo/nest-messages.md | 2 +- components/form/demo/normal-login.md | 2 +- components/form/demo/register.md | 9 +- components/form/demo/required-mark.md | 6 +- components/form/demo/size.md | 10 ++- components/form/demo/time-related-controls.md | 6 +- components/form/demo/validate-other.md | 4 +- components/form/demo/without-form-create.md | 14 ++- components/mentions/demo/form.md | 6 +- .../__tests__/__snapshots__/demo.test.js.snap | 40 ++++++--- components/table/demo/edit-cell.md | 50 +++++++---- components/table/demo/edit-row.md | 8 +- components/table/demo/row-selection.md | 18 ++-- components/table/demo/virtual-list.md | 30 ++++--- components/tree/demo/basic-controlled.md | 12 +-- components/tree/demo/basic.md | 4 +- components/tree/demo/directory.md | 4 +- components/tree/demo/dynamic.md | 4 +- components/tree/demo/line.md | 14 +-- components/upload/Upload.tsx | 1 + components/upload/interface.tsx | 15 +--- package.json | 6 +- scripts/check-ts-demo.js | 88 +++++++++++++++++++ typings/custom-typings.d.ts | 2 - 43 files changed, 330 insertions(+), 150 deletions(-) create mode 100644 scripts/check-ts-demo.js diff --git a/.eslintignore b/.eslintignore index 40e29b4ac4..b4e2cb7be0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ components/**/*.jsx !components/*/__tests__/**/*.js !components/*/demo/* !.*.js +~* # Docs templates site/theme/template/Color/ColorPicker.jsx site/theme/template/IconDisplay/*.js @@ -27,4 +28,4 @@ coverage **/*.d.ts # Scripts scripts/previewEditor/**/* -jest-stare +jest-stare \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 209aefdbc7..35bfc4e602 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,6 +95,28 @@ jobs: run: npm run lint needs: setup + tsx-demo: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: restore cache from package-lock.json + uses: actions/cache@v2 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: restore cache from node_modules + uses: actions/cache@v2 + with: + path: node_modules + key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }} + + - name: tsx-demo + run: npm run check-ts-demo + needs: setup + check_metadata: runs-on: ubuntu-latest steps: diff --git a/components/affix/demo/target.md b/components/affix/demo/target.md index 9b1f206d35..a938374c8d 100644 --- a/components/affix/demo/target.md +++ b/components/affix/demo/target.md @@ -18,7 +18,7 @@ import React, { useState } from 'react'; import { Affix, Button } from 'antd'; const Demo: React.FC = () => { - const [container, setContainer] = useState(null); + const [container, setContainer] = useState(null); return (
diff --git a/components/alert/__tests__/__snapshots__/demo.test.ts.snap b/components/alert/__tests__/__snapshots__/demo.test.ts.snap index 312585e3f2..5c781b14de 100644 --- a/components/alert/__tests__/__snapshots__/demo.test.ts.snap +++ b/components/alert/__tests__/__snapshots__/demo.test.ts.snap @@ -996,7 +996,7 @@ Array [ exports[`renders ./components/alert/demo/error-boundary.md correctly 1`] = ` ); diff --git a/components/auto-complete/demo/non-case-sensitive.md b/components/auto-complete/demo/non-case-sensitive.md index 839db06c64..ac8a04a2a6 100644 --- a/components/auto-complete/demo/non-case-sensitive.md +++ b/components/auto-complete/demo/non-case-sensitive.md @@ -28,7 +28,7 @@ const Complete: React.FC = () => ( options={options} placeholder="try to type `b`" filterOption={(inputValue, option) => - option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1 + option!.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1 } /> ); diff --git a/components/auto-complete/demo/uncertain-category.md b/components/auto-complete/demo/uncertain-category.md index 7a23b54996..31116aa7b9 100644 --- a/components/auto-complete/demo/uncertain-category.md +++ b/components/auto-complete/demo/uncertain-category.md @@ -26,7 +26,7 @@ const searchResult = (query: string) => { return new Array(getRandomInt(5)) .join('.') .split('.') - .map((item, idx) => { + .map((_, idx) => { const category = `${query}${idx}`; return { value: category, diff --git a/components/drawer/demo/config-provider.md b/components/drawer/demo/config-provider.md index d46aecea08..0d9739b0a9 100644 --- a/components/drawer/demo/config-provider.md +++ b/components/drawer/demo/config-provider.md @@ -19,7 +19,7 @@ import React, { useState, useRef } from 'react'; import { Drawer, ConfigProvider, Button } from 'antd'; const App: React.FC = () => { - const domRef = useRef(); + const domRef = useRef(null); const [visible, setVisible] = useState(false); const showDrawer = () => { setVisible(true); @@ -30,7 +30,7 @@ const App: React.FC = () => { return ( { - return domRef.current; + return domRef.current!; }} >
diff --git a/components/form/demo/advanced-search.md b/components/form/demo/advanced-search.md index 0329e48d7d..a000c7b37f 100644 --- a/components/form/demo/advanced-search.md +++ b/components/form/demo/advanced-search.md @@ -52,7 +52,7 @@ const AdvancedSearchForm = () => { return children; }; - const onFinish = values => { + const onFinish = (values: any) => { console.log('Received values of form: ', values); }; diff --git a/components/form/demo/basic.md b/components/form/demo/basic.md index 9e8fd5f4c8..2d7c0e2c4d 100644 --- a/components/form/demo/basic.md +++ b/components/form/demo/basic.md @@ -25,11 +25,11 @@ const tailLayout = { }; const Demo = () => { - const onFinish = values => { + const onFinish = (values: any) => { console.log('Success:', values); }; - const onFinishFailed = errorInfo => { + const onFinishFailed = (errorInfo: any) => { console.log('Failed:', errorInfo); }; diff --git a/components/form/demo/control-hooks.md b/components/form/demo/control-hooks.md index c985e674e6..7b8a206717 100644 --- a/components/form/demo/control-hooks.md +++ b/components/form/demo/control-hooks.md @@ -33,7 +33,7 @@ const tailLayout = { const Demo = () => { const [form] = Form.useForm(); - const onGenderChange = value => { + const onGenderChange = (value: string) => { switch (value) { case 'male': form.setFieldsValue({ note: 'Hi, man!' }); @@ -47,7 +47,7 @@ const Demo = () => { } }; - const onFinish = values => { + const onFinish = (values: any) => { console.log(values); }; diff --git a/components/form/demo/control-ref.md b/components/form/demo/control-ref.md index 899b406e9d..d5112d8473 100644 --- a/components/form/demo/control-ref.md +++ b/components/form/demo/control-ref.md @@ -30,30 +30,30 @@ const tailLayout = { class Demo extends React.Component { formRef = React.createRef(); - onGenderChange = value => { + onGenderChange = (value: string) => { switch (value) { case 'male': - this.formRef.current.setFieldsValue({ note: 'Hi, man!' }); + this.formRef.current!.setFieldsValue({ note: 'Hi, man!' }); return; case 'female': - this.formRef.current.setFieldsValue({ note: 'Hi, lady!' }); + this.formRef.current!.setFieldsValue({ note: 'Hi, lady!' }); return; case 'other': - this.formRef.current.setFieldsValue({ note: 'Hi there!' }); + this.formRef.current!.setFieldsValue({ note: 'Hi there!' }); return; } }; - onFinish = values => { + onFinish = (values: any) => { console.log(values); }; onReset = () => { - this.formRef.current.resetFields(); + this.formRef.current!.resetFields(); }; onFill = () => { - this.formRef.current.setFieldsValue({ + this.formRef.current!.setFieldsValue({ note: 'Hello world!', gender: 'male', }); diff --git a/components/form/demo/customized-form-controls.md b/components/form/demo/customized-form-controls.md index 6e8e0b6ac9..7a3a797d13 100644 --- a/components/form/demo/customized-form-controls.md +++ b/components/form/demo/customized-form-controls.md @@ -25,9 +25,11 @@ import { Form, Input, Select, Button } from 'antd'; const { Option } = Select; +type Currency = 'rmb' | 'dollar'; + interface PriceValue { number?: number; - currency?: 'rmb' | 'dollar'; + currency?: Currency; } interface PriceInputProps { @@ -37,16 +39,16 @@ interface PriceInputProps { const PriceInput: React.FC = ({ value = {}, onChange }) => { const [number, setNumber] = useState(0); - const [currency, setCurrency] = useState('rmb'); + const [currency, setCurrency] = useState('rmb'); - const triggerChange = changedValue => { + const triggerChange = (changedValue: { number?: number; currency?: Currency }) => { if (onChange) { onChange({ number, currency, ...value, ...changedValue }); } }; - const onNumberChange = e => { - const newNumber = parseInt(e.target.value || 0, 10); + const onNumberChange = (e: React.ChangeEvent) => { + const newNumber = parseInt(e.target.value || '0', 10); if (Number.isNaN(number)) { return; } @@ -56,7 +58,7 @@ const PriceInput: React.FC = ({ value = {}, onChange }) => { triggerChange({ number: newNumber }); }; - const onCurrencyChange = newCurrency => { + const onCurrencyChange = (newCurrency: Currency) => { if (!('currency' in value)) { setCurrency(newCurrency); } @@ -84,11 +86,11 @@ const PriceInput: React.FC = ({ value = {}, onChange }) => { }; const Demo = () => { - const onFinish = values => { + const onFinish = (values: any) => { console.log('Received values from form: ', values); }; - const checkPrice = (rule, value) => { + const checkPrice = (_: any, value: { number: number }) => { if (value.number > 0) { return Promise.resolve(); } diff --git a/components/form/demo/dynamic-rule.md b/components/form/demo/dynamic-rule.md index 84f930a5bf..0c0efbe8ba 100644 --- a/components/form/demo/dynamic-rule.md +++ b/components/form/demo/dynamic-rule.md @@ -34,7 +34,7 @@ const DynamicRule = () => { form.validateFields(['nickname']); }, [checkNick]); - const onCheckboxChange = e => { + const onCheckboxChange = (e: { target: { checked: boolean } }) => { setCheckNick(e.target.checked); }; diff --git a/components/form/demo/form-context.md b/components/form/demo/form-context.md index d917ecea05..f03c26f536 100644 --- a/components/form/demo/form-context.md +++ b/components/form/demo/form-context.md @@ -17,6 +17,7 @@ Use `Form.Provider` to process data between forms. In this case, submit button i import React, { useState, useEffect, useRef } from 'react'; import { Form, Input, InputNumber, Modal, Button, Avatar, Typography } from 'antd'; import { SmileOutlined, UserOutlined } from '@ant-design/icons'; +import { FormInstance } from 'antd/lib/form'; const layout = { labelCol: { span: 8 }, @@ -26,14 +27,19 @@ const tailLayout = { wrapperCol: { offset: 8, span: 16 }, }; +interface UserType { + name: string; + age: string; +} + interface ModalFormProps { visible: boolean; onCancel: () => void; } // reset form fields when modal is form, closed -const useResetFormOnCloseModal = ({ form, visible }) => { - const prevVisibleRef = useRef(); +const useResetFormOnCloseModal = ({ form, visible }: { form: FormInstance; visible: boolean }) => { + const prevVisibleRef = useRef(); useEffect(() => { prevVisibleRef.current = visible; }, [visible]); @@ -83,7 +89,7 @@ const Demo = () => { setVisible(false); }; - const onFinish = values => { + const onFinish = (values: any) => { console.log('Finish:', values); }; @@ -108,7 +114,7 @@ const Demo = () => { shouldUpdate={(prevValues, curValues) => prevValues.users !== curValues.users} > {({ getFieldValue }) => { - const users = getFieldValue('users') || []; + const users: UserType[] = getFieldValue('users') || []; return users.length ? (
    {users.map((user, index) => ( diff --git a/components/form/demo/form-in-modal.md b/components/form/demo/form-in-modal.md index 9521ddd194..c4fa1b2dbd 100644 --- a/components/form/demo/form-in-modal.md +++ b/components/form/demo/form-in-modal.md @@ -86,7 +86,7 @@ const CollectionCreateForm: React.FC = ({ const CollectionsPage = () => { const [visible, setVisible] = useState(false); - const onCreate = values => { + const onCreate = (values: any) => { console.log('Received values of form: ', values); setVisible(false); }; diff --git a/components/form/demo/global-state.md b/components/form/demo/global-state.md index f20c1bfac4..e1f0f31368 100644 --- a/components/form/demo/global-state.md +++ b/components/form/demo/global-state.md @@ -22,11 +22,11 @@ import React, { useState } from 'react'; import { Form, Input } from 'antd'; interface FieldData { - name: string[]; - value: any; - touched: boolean; - validating: boolean; - errors: string[]; + name: string | number | (string | number)[]; + value?: any; + touched?: boolean; + validating?: boolean; + errors?: string[]; } interface CustomizedFormProps { @@ -40,7 +40,7 @@ const CustomizedForm: React.FC = ({ onChange, fields }) => name="global_state" layout="inline" fields={fields} - onFieldsChange={(changedFields, allFields) => { + onFieldsChange={(_, allFields) => { onChange(allFields); }} > @@ -56,7 +56,7 @@ const CustomizedForm: React.FC = ({ onChange, fields }) => }; const Demo = () => { - const [fields, setFields] = useState([{ name: ['username'], value: 'Ant Design' }]); + const [fields, setFields] = useState([{ name: ['username'], value: 'Ant Design' }]); return ( <> diff --git a/components/form/demo/inline-login.md b/components/form/demo/inline-login.md index fa921c4c73..72218dbc80 100644 --- a/components/form/demo/inline-login.md +++ b/components/form/demo/inline-login.md @@ -20,14 +20,14 @@ import { UserOutlined, LockOutlined } from '@ant-design/icons'; const HorizontalLoginForm = () => { const [form] = Form.useForm(); - const [, forceUpdate] = useState(); + const [, forceUpdate] = useState({}); // To disable submit button at the beginning. useEffect(() => { forceUpdate({}); }, []); - const onFinish = values => { + const onFinish = (values: any) => { console.log('Finish:', values); }; @@ -56,7 +56,7 @@ const HorizontalLoginForm = () => { htmlType="submit" disabled={ !form.isFieldsTouched(true) || - form.getFieldsError().filter(({ errors }) => errors.length).length + !!form.getFieldsError().filter(({ errors }) => errors.length).length } > Log in diff --git a/components/form/demo/layout.md b/components/form/demo/layout.md index ca2b747249..b15361faa1 100644 --- a/components/form/demo/layout.md +++ b/components/form/demo/layout.md @@ -17,11 +17,13 @@ There are three layout for form: `horizontal`, `vertical`, `inline`. import React, { useState } from 'react'; import { Form, Input, Button, Radio } from 'antd'; +type LayoutType = Parameters[0]['layout']; + const FormLayoutDemo = () => { const [form] = Form.useForm(); - const [formLayout, setFormLayout] = useState('horizontal'); + const [formLayout, setFormLayout] = useState('horizontal'); - const onFormLayoutChange = ({ layout }) => { + const onFormLayoutChange = ({ layout }: { layout: LayoutType }) => { setFormLayout(layout); }; diff --git a/components/form/demo/nest-messages.md b/components/form/demo/nest-messages.md index 046f5af521..cdc12797f6 100644 --- a/components/form/demo/nest-messages.md +++ b/components/form/demo/nest-messages.md @@ -33,7 +33,7 @@ const validateMessages = { }; const Demo = () => { - const onFinish = values => { + const onFinish = (values: any) => { console.log(values); }; diff --git a/components/form/demo/normal-login.md b/components/form/demo/normal-login.md index 3bbd95a8a3..fb51679f47 100644 --- a/components/form/demo/normal-login.md +++ b/components/form/demo/normal-login.md @@ -20,7 +20,7 @@ import { Form, Input, Button, Checkbox } from 'antd'; import { UserOutlined, LockOutlined } from '@ant-design/icons'; const NormalLoginForm = () => { - const onFinish = values => { + const onFinish = (values: any) => { console.log('Received values of form: ', values); }; diff --git a/components/form/demo/register.md b/components/form/demo/register.md index 4d0b9aa334..2051c98d1f 100644 --- a/components/form/demo/register.md +++ b/components/form/demo/register.md @@ -30,7 +30,6 @@ import { import { QuestionCircleOutlined } from '@ant-design/icons'; const { Option } = Select; -const AutoCompleteOption = AutoComplete.Option; const residences = [ { @@ -93,7 +92,7 @@ const tailFormItemLayout = { const RegistrationForm = () => { const [form] = Form.useForm(); - const onFinish = values => { + const onFinish = (values: any) => { console.log('Received values of form: ', values); }; @@ -106,9 +105,9 @@ const RegistrationForm = () => { ); - const [autoCompleteResult, setAutoCompleteResult] = useState([]); + const [autoCompleteResult, setAutoCompleteResult] = useState([]); - const onWebsiteChange = value => { + const onWebsiteChange = (value: string) => { if (!value) { setAutoCompleteResult([]); } else { @@ -175,7 +174,7 @@ const RegistrationForm = () => { message: 'Please confirm your password!', }, ({ getFieldValue }) => ({ - validator(rule, value) { + validator(_, value) { if (!value || getFieldValue('password') === value) { return Promise.resolve(); } diff --git a/components/form/demo/required-mark.md b/components/form/demo/required-mark.md index 246ba46ed9..116cf9e35a 100644 --- a/components/form/demo/required-mark.md +++ b/components/form/demo/required-mark.md @@ -18,11 +18,13 @@ import React, { useState } from 'react'; import { Form, Input, Button, Radio } from 'antd'; import { InfoCircleOutlined } from '@ant-design/icons'; +type RequiredMark = boolean | 'optional'; + const FormLayoutDemo = () => { const [form] = Form.useForm(); - const [requiredMark, setRequiredMarkType] = useState('optional'); + const [requiredMark, setRequiredMarkType] = useState('optional'); - const onRequiredTypeChange = ({ requiredMark }) => { + const onRequiredTypeChange = ({ requiredMark }: { requiredMark: RequiredMark }) => { setRequiredMarkType(requiredMark); }; diff --git a/components/form/demo/size.md b/components/form/demo/size.md index 9a602dc179..b530b4fbf7 100644 --- a/components/form/demo/size.md +++ b/components/form/demo/size.md @@ -27,9 +27,12 @@ import { TreeSelect, Switch, } from 'antd'; + +type SizeType = Parameters[0]['size']; + const FormSizeDemo = () => { - const [componentSize, setComponentSize] = useState('default'); - const onFormLayoutChange = ({ size }) => { + const [componentSize, setComponentSize] = useState('default'); + const onFormLayoutChange = ({ size }: { size: SizeType }) => { setComponentSize(size); }; return ( @@ -40,7 +43,7 @@ const FormSizeDemo = () => { layout="horizontal" initialValues={{ size: componentSize }} onValuesChange={onFormLayoutChange} - size={componentSize} + size={componentSize as SizeType} > @@ -96,5 +99,6 @@ const FormSizeDemo = () => { ); }; + ReactDOM.render(, mountNode); ``` diff --git a/components/form/demo/time-related-controls.md b/components/form/demo/time-related-controls.md index 3688aff21a..6929abc12f 100644 --- a/components/form/demo/time-related-controls.md +++ b/components/form/demo/time-related-controls.md @@ -29,14 +29,14 @@ const formItemLayout = { }, }; const config = { - rules: [{ type: 'object', required: true, message: 'Please select time!' }], + rules: [{ type: 'object' as const, required: true, message: 'Please select time!' }], }; const rangeConfig = { - rules: [{ type: 'array', required: true, message: 'Please select time!' }], + rules: [{ type: 'array' as const, required: true, message: 'Please select time!' }], }; const TimeRelatedForm = () => { - const onFinish = fieldsValue => { + const onFinish = (fieldsValue: any) => { // Should format date value before submit. const rangeValue = fieldsValue['range-picker']; const rangeTimeValue = fieldsValue['range-time-picker']; diff --git a/components/form/demo/validate-other.md b/components/form/demo/validate-other.md index deb7d8c635..9f8efaaa7c 100644 --- a/components/form/demo/validate-other.md +++ b/components/form/demo/validate-other.md @@ -37,7 +37,7 @@ const formItemLayout = { wrapperCol: { span: 14 }, }; -const normFile = e => { +const normFile = (e: any) => { console.log('Upload event:', e); if (Array.isArray(e)) { return e; @@ -46,7 +46,7 @@ const normFile = e => { }; const Demo = () => { - const onFinish = values => { + const onFinish = (values: any) => { console.log('Received values of form: ', values); }; diff --git a/components/form/demo/without-form-create.md b/components/form/demo/without-form-create.md index 25ef47d7fd..758c0ee78f 100644 --- a/components/form/demo/without-form-create.md +++ b/components/form/demo/without-form-create.md @@ -17,7 +17,11 @@ title: import React, { useState } from 'react'; import { Form, InputNumber } from 'antd'; -function validatePrimeNumber(number) { +type ValidateStatus = Parameters[0]['validateStatus']; + +function validatePrimeNumber( + number: number, +): { validateStatus: ValidateStatus; errorMsg: string | null } { if (number === 11) { return { validateStatus: 'success', @@ -36,14 +40,18 @@ const formItemLayout = { }; const RawForm = () => { - const [number, setNumber] = useState({ + const [number, setNumber] = useState<{ + value: number; + validateStatus?: ValidateStatus; + errorMsg?: string | null; + }>({ value: 11, }); const tips = 'A prime is a natural number greater than 1 that has no positive divisors other than 1 and itself.'; - const onNumberChange = value => { + const onNumberChange = (value: number) => { setNumber({ ...validatePrimeNumber(value), value, diff --git a/components/mentions/demo/form.md b/components/mentions/demo/form.md index 25d110e9e4..5ed4bb7f38 100644 --- a/components/mentions/demo/form.md +++ b/components/mentions/demo/form.md @@ -34,7 +34,7 @@ const App = () => { } }; - const checkMention = async (rule, value, callback) => { + const checkMention = async (_: any, value: string) => { const mentions = getMentions(value); if (mentions.length < 2) { @@ -51,7 +51,7 @@ const App = () => { wrapperCol={{ span: 16 }} rules={[{ validator: checkMention }]} > - + @@ -64,7 +64,7 @@ const App = () => { wrapperCol={{ span: 16 }} rules={[{ required: true }]} > - + diff --git a/components/table/__tests__/__snapshots__/demo.test.js.snap b/components/table/__tests__/__snapshots__/demo.test.js.snap index 25ad0641dc..69709be8fc 100644 --- a/components/table/__tests__/__snapshots__/demo.test.js.snap +++ b/components/table/__tests__/__snapshots__/demo.test.js.snap @@ -4166,7 +4166,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4193,7 +4195,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4220,7 +4224,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4247,7 +4253,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4274,7 +4282,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4301,7 +4311,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4328,7 +4340,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4355,7 +4369,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4382,7 +4398,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit @@ -4409,7 +4427,9 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = ` - + Edit diff --git a/components/table/demo/edit-cell.md b/components/table/demo/edit-cell.md index cee0957c05..80734ee99e 100644 --- a/components/table/demo/edit-cell.md +++ b/components/table/demo/edit-cell.md @@ -16,8 +16,9 @@ Table with editable cells. ```tsx import React, { useContext, useState, useEffect, useRef } from 'react'; import { Table, Input, Button, Popconfirm, Form } from 'antd'; +import { FormInstance } from 'antd/lib/form'; -const EditableContext = React.createContext(); +const EditableContext = React.createContext | null>(null); interface Item { key: string; @@ -45,7 +46,7 @@ interface EditableCellProps { title: React.ReactNode; editable: boolean; children: React.ReactNode; - dataIndex: string; + dataIndex: keyof Item; record: Item; handleSave: (record: Item) => void; } @@ -60,12 +61,12 @@ const EditableCell: React.FC = ({ ...restProps }) => { const [editing, setEditing] = useState(false); - const inputRef = useRef(); - const form = useContext(EditableContext); + const inputRef = useRef(null); + const form = useContext(EditableContext)!; useEffect(() => { if (editing) { - inputRef.current.focus(); + inputRef.current!.focus(); } }, [editing]); @@ -74,7 +75,7 @@ const EditableCell: React.FC = ({ form.setFieldsValue({ [dataIndex]: record[dataIndex] }); }; - const save = async e => { + const save = async () => { try { const values = await form.validateFields(); @@ -111,9 +112,28 @@ const EditableCell: React.FC = ({ return {childNode}; }; -class EditableTable extends React.Component { - constructor(props) { +type EditableTableProps = Parameters[0]; + +interface DataType { + key: React.Key; + name: string; + age: string; + address: string; +} + +interface EditableTableState { + dataSource: DataType[]; + count: number; +} + +type ColumnTypes = Exclude; + +class EditableTable extends React.Component { + columns: (ColumnTypes[number] & { editable?: boolean; dataIndex: string })[]; + + constructor(props: EditableTableProps) { super(props); + this.columns = [ { title: 'name', @@ -132,7 +152,7 @@ class EditableTable extends React.Component { { title: 'operation', dataIndex: 'operation', - render: (text, record) => + render: (_, record: { key: React.Key }) => this.state.dataSource.length >= 1 ? ( this.handleDelete(record.key)}> Delete @@ -160,17 +180,17 @@ class EditableTable extends React.Component { }; } - handleDelete = key => { + handleDelete = (key: React.Key) => { const dataSource = [...this.state.dataSource]; this.setState({ dataSource: dataSource.filter(item => item.key !== key) }); }; handleAdd = () => { const { count, dataSource } = this.state; - const newData = { + const newData: DataType = { key: count, name: `Edward King ${count}`, - age: 32, + age: '32', address: `London, Park Lane no. ${count}`, }; this.setState({ @@ -179,7 +199,7 @@ class EditableTable extends React.Component { }); }; - handleSave = row => { + handleSave = (row: DataType) => { const newData = [...this.state.dataSource]; const index = newData.findIndex(item => row.key === item.key); const item = newData[index]; @@ -204,7 +224,7 @@ class EditableTable extends React.Component { } return { ...col, - onCell: record => ({ + onCell: (record: DataType) => ({ record, editable: col.editable, dataIndex: col.dataIndex, @@ -223,7 +243,7 @@ class EditableTable extends React.Component { rowClassName={() => 'editable-row'} bordered dataSource={dataSource} - columns={columns} + columns={columns as ColumnTypes} />
); diff --git a/components/table/demo/edit-row.md b/components/table/demo/edit-row.md index f6beeaf454..053070791e 100644 --- a/components/table/demo/edit-row.md +++ b/components/table/demo/edit-row.md @@ -17,7 +17,7 @@ Table with editable rows. ```tsx import React, { useState } from 'react'; -import { Table, Input, InputNumber, Popconfirm, Form } from 'antd'; +import { Table, Input, InputNumber, Popconfirm, Form, Typography } from 'antd'; interface Item { key: string; @@ -86,7 +86,7 @@ const EditableTable = () => { const isEditing = (record: Item) => record.key === editingKey; - const edit = (record: Item) => { + const edit = (record: Partial & { key: React.Key }) => { form.setFieldsValue({ name: '', age: '', address: '', ...record }); setEditingKey(record.key); }; @@ -153,9 +153,9 @@ const EditableTable = () => { ) : ( - edit(record)}> + edit(record)}> Edit - + ); }, }, diff --git a/components/table/demo/row-selection.md b/components/table/demo/row-selection.md index 3afaf58fed..3d74756572 100644 --- a/components/table/demo/row-selection.md +++ b/components/table/demo/row-selection.md @@ -25,7 +25,7 @@ const columns = [ { title: 'Name', dataIndex: 'name', - render: text => {text}, + render: (text: string) => {text}, }, { title: 'Age', @@ -36,7 +36,15 @@ const columns = [ dataIndex: 'address', }, ]; -const data = [ + +interface DataType { + key: React.Key; + name: string; + age: number; + address: string; +} + +const data: DataType[] = [ { key: '1', name: 'John Brown', @@ -65,17 +73,17 @@ const data = [ // rowSelection object indicates the need for row selection const rowSelection = { - onChange: (selectedRowKeys, selectedRows) => { + onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => { console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows); }, - getCheckboxProps: record => ({ + getCheckboxProps: (record: DataType) => ({ disabled: record.name === 'Disabled User', // Column configuration not to be checked name: record.name, }), }; const Demo = () => { - const [selectionType, setSelectionType] = useState('checkbox'); + const [selectionType, setSelectionType] = useState<'checkbox' | 'radio'>('checkbox'); return (
diff --git a/components/table/demo/virtual-list.md b/components/table/demo/virtual-list.md index b0ac712144..849120c3d2 100644 --- a/components/table/demo/virtual-list.md +++ b/components/table/demo/virtual-list.md @@ -20,12 +20,12 @@ import ResizeObserver from 'rc-resize-observer'; import classNames from 'classnames'; import { Table } from 'antd'; -function VirtualTable(props) { +function VirtualTable(props: Parameters[0]) { const { columns, scroll } = props; const [tableWidth, setTableWidth] = useState(0); - const widthColumnCount = columns.filter(({ width }) => !width).length; - const mergedColumns = columns.map(column => { + const widthColumnCount = columns!.filter(({ width }) => !width).length; + const mergedColumns = columns!.map(column => { if (column.width) { return column; } @@ -69,28 +69,36 @@ function VirtualTable(props) { ref={gridRef} className="virtual-grid" columnCount={mergedColumns.length} - columnWidth={index => { + columnWidth={(index: number) => { const { width } = mergedColumns[index]; - return totalHeight > scroll.y && index === mergedColumns.length - 1 - ? width - scrollbarSize - 1 - : width; + return totalHeight > scroll!.y! && index === mergedColumns.length - 1 + ? (width as number) - scrollbarSize - 1 + : (width as number); }} - height={scroll.y} + height={scroll!.y as number} rowCount={rawData.length} rowHeight={() => 54} width={tableWidth} - onScroll={({ scrollLeft }) => { + onScroll={({ scrollLeft }: { scrollLeft: number }) => { onScroll({ scrollLeft }); }} > - {({ columnIndex, rowIndex, style }) => ( + {({ + columnIndex, + rowIndex, + style, + }: { + columnIndex: number; + rowIndex: number; + style: React.CSSProperties; + }) => (
- {rawData[rowIndex][mergedColumns[columnIndex].dataIndex]} + {(rawData[rowIndex] as any)[(mergedColumns as any)[columnIndex].dataIndex]}
)} diff --git a/components/tree/demo/basic-controlled.md b/components/tree/demo/basic-controlled.md index 4be7c19f69..08798df102 100644 --- a/components/tree/demo/basic-controlled.md +++ b/components/tree/demo/basic-controlled.md @@ -62,12 +62,12 @@ const treeData = [ ]; const Demo = () => { - const [expandedKeys, setExpandedKeys] = useState(['0-0-0', '0-0-1']); - const [checkedKeys, setCheckedKeys] = useState(['0-0-0']); - const [selectedKeys, setSelectedKeys] = useState([]); + const [expandedKeys, setExpandedKeys] = useState(['0-0-0', '0-0-1']); + const [checkedKeys, setCheckedKeys] = useState(['0-0-0']); + const [selectedKeys, setSelectedKeys] = useState([]); const [autoExpandParent, setAutoExpandParent] = useState(true); - const onExpand = expandedKeys => { + const onExpand = (expandedKeys: React.Key[]) => { console.log('onExpand', expandedKeys); // if not set autoExpandParent to false, if children expanded, parent can not collapse. // or, you can remove all expanded children keys. @@ -75,12 +75,12 @@ const Demo = () => { setAutoExpandParent(false); }; - const onCheck = checkedKeys => { + const onCheck = (checkedKeys: React.Key[]) => { console.log('onCheck', checkedKeys); setCheckedKeys(checkedKeys); }; - const onSelect = (selectedKeys, info) => { + const onSelect = (selectedKeys: React.Key[], info: any) => { console.log('onSelect', info); setSelectedKeys(selectedKeys); }; diff --git a/components/tree/demo/basic.md b/components/tree/demo/basic.md index e1dcb3ec87..67f2d77a8b 100644 --- a/components/tree/demo/basic.md +++ b/components/tree/demo/basic.md @@ -47,11 +47,11 @@ const treeData = [ ]; const Demo = () => { - const onSelect = (selectedKeys, info) => { + const onSelect = (selectedKeys: React.Key[], info: any) => { console.log('selected', selectedKeys, info); }; - const onCheck = (checkedKeys, info) => { + const onCheck = (checkedKeys: React.Key[], info: any) => { console.log('onCheck', checkedKeys, info); }; diff --git a/components/tree/demo/directory.md b/components/tree/demo/directory.md index c9a7841cf0..326aafe94c 100644 --- a/components/tree/demo/directory.md +++ b/components/tree/demo/directory.md @@ -38,8 +38,8 @@ const treeData = [ ]; const Demo: React.FC<{}> = () => { - const onSelect = (keys, event) => { - console.log('Trigger Select', keys, event); + const onSelect = (keys: React.Key[], info: any) => { + console.log('Trigger Select', keys, info); }; const onExpand = () => { diff --git a/components/tree/demo/dynamic.md b/components/tree/demo/dynamic.md index af20ce40c9..453dc8bede 100644 --- a/components/tree/demo/dynamic.md +++ b/components/tree/demo/dynamic.md @@ -51,8 +51,8 @@ function updateTreeData(list: DataNode[], key: React.Key, children: DataNode[]): const Demo: React.FC<{}> = () => { const [treeData, setTreeData] = useState(initTreeDate); - function onLoadData({ key, children }) { - return new Promise(resolve => { + function onLoadData({ key, children }: any) { + return new Promise(resolve => { if (children) { resolve(); return; diff --git a/components/tree/demo/line.md b/components/tree/demo/line.md index 030c27cfc2..6bb03fb630 100644 --- a/components/tree/demo/line.md +++ b/components/tree/demo/line.md @@ -84,20 +84,20 @@ const treeData = [ ]; const Demo: React.FC<{}> = () => { - const [showLine, setShowLine] = useState(true); - const [showIcon, setShowIcon] = useState(false); - const [showLeafIcon, setShowLeafIcon] = useState(true); + const [showLine, setShowLine] = useState(true); + const [showIcon, setShowIcon] = useState(false); + const [showLeafIcon, setShowLeafIcon] = useState(true); - const onSelect = (selectedKeys, info) => { + const onSelect = (selectedKeys: React.Key[], info: any) => { console.log('selected', selectedKeys, info); }; - const onSetLeafIcon = checked => { + const onSetLeafIcon = (checked: boolean) => { setShowLeafIcon(checked); setShowLine({ showLeafIcon: checked }); }; - const onSetShowLine = checked => { + const onSetShowLine = (checked: boolean) => { if (checked) { showLeafIcon ? setShowLine(checked) : setShowLine({ showLeafIcon }); } else { @@ -108,7 +108,7 @@ const Demo: React.FC<{}> = () => { return (
- showLine: + showLine:

showIcon: diff --git a/components/upload/Upload.tsx b/components/upload/Upload.tsx index a5efd72c61..ae7f7d21bc 100644 --- a/components/upload/Upload.tsx +++ b/components/upload/Upload.tsx @@ -231,6 +231,7 @@ const InternalUpload: React.ForwardRefRenderFunction = (pr ...props, prefixCls, beforeUpload, + onChange: undefined, }; delete rcUploadProps.className; diff --git a/components/upload/interface.tsx b/components/upload/interface.tsx index 44680f365e..0a5ff4a57e 100755 --- a/components/upload/interface.tsx +++ b/components/upload/interface.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { UploadRequestOption as RcCustomRequestOptions } from 'rc-upload/lib/interface'; import { ProgressProps } from '../progress'; export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed'; @@ -13,18 +14,6 @@ export interface RcFile extends File { readonly webkitRelativePath: string; } -export interface RcCustomRequestOptions { - onProgress: (event: { percent: number }, file: RcFile) => void; - onError: (error: Error, response?: any, file?: RcFile) => void; - onSuccess: (response: object, file: RcFile) => void; - data: object; - filename: string; - file: RcFile; - withCredentials: boolean; - action: string; - headers: object; -} - export interface UploadFile { uid: string; size: number; @@ -96,7 +85,7 @@ export interface UploadProps { showUploadList?: boolean | ShowUploadListInterface; multiple?: boolean; accept?: string; - beforeUpload?: (file: RcFile, FileList: RcFile[]) => boolean | PromiseLike; + beforeUpload?: (file: RcFile, FileList: RcFile[]) => boolean | Promise; onChange?: (info: UploadChangeParam) => void; listType?: UploadListType; className?: string; diff --git a/package.json b/package.json index acc522d7e2..2ec0b35057 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "build": "npm run compile && NODE_OPTIONS='--max-old-space-size=4096' npm run dist", "bundlesize": "bundlesize", "check-commit": "node ./scripts/check-commit", + "check-ts-demo": "node ./scripts/check-ts-demo", "prestart": "npm run version", "precompile": "npm run version", "pretest": "npm run version", @@ -122,7 +123,7 @@ "rc-dialog": "~8.4.0", "rc-drawer": "~4.1.0", "rc-dropdown": "~3.2.0", - "rc-field-form": "~1.17.0", + "rc-field-form": "~1.17.3", "rc-image": "~4.2.0", "rc-input-number": "~6.1.0", "rc-mentions": "~1.5.0", @@ -144,7 +145,7 @@ "rc-tooltip": "~5.0.0", "rc-tree": "~4.0.0", "rc-tree-select": "~4.2.0", - "rc-upload": "~3.3.1", + "rc-upload": "~3.3.4", "rc-util": "^5.1.0", "scroll-into-view-if-needed": "^2.2.25", "warning": "^4.0.3" @@ -167,6 +168,7 @@ "@types/react-color": "^3.0.1", "@types/react-copy-to-clipboard": "^5.0.0", "@types/react-dom": "^17.0.0", + "@types/react-window": "^1.8.2", "@types/warning": "^3.0.0", "@typescript-eslint/eslint-plugin": "^4.1.1", "@typescript-eslint/parser": "^4.1.1", diff --git a/scripts/check-ts-demo.js b/scripts/check-ts-demo.js new file mode 100644 index 0000000000..1111e39f0a --- /dev/null +++ b/scripts/check-ts-demo.js @@ -0,0 +1,88 @@ +/* eslint-disable no-await-in-loop, no-console */ + +const path = require('path'); +const glob = require('glob'); +const fs = require('fs-extra'); +const chalk = require('chalk'); +const { spawn } = require('child_process'); + +(async () => { + console.time('Execution...'); + + const demoFiles = glob.sync(path.join(process.cwd(), 'components/**/demo/*.md')); + + const tmpFolder = path.resolve('components', '~tmp'); + await fs.remove(tmpFolder); + await fs.ensureDir(tmpFolder); + + function getTypescriptDemo(content, demoPath) { + const lines = content.split(/[\n\r]/); + + const tsxStartLine = lines.findIndex(line => + line.replace(/\s/g).toLowerCase().includes('```tsx'), + ); + + if (tsxStartLine < 0) { + return null; + } + + const tsxEndLine = lines.findIndex( + (line, index) => index > tsxStartLine && line.trim() === '```', + ); + + let script = lines.slice(tsxStartLine + 1, tsxEndLine).join('\n'); + + // insert React & ReactDOM + if (!script.includes('import React') && !script.includes('import * as React')) { + script = `import React from 'react';\n${script}`; + } + script = `import ReactDOM from 'react-dom';\n${script}`; + + // Replace mountNode + script = script.replace('mountNode', `document.getElementById('#root')`); + + // Replace antd + script = script.replace(`from 'antd'`, `from '..'`); + + // Add path + script = `/* eslint-disabled */\n// ${demoPath}\n${script}`; + + return script; + } + + for (let i = 0; i < demoFiles.length; i += 1) { + const demoPath = demoFiles[i]; + + const content = await fs.readFile(demoPath, 'utf8'); + const script = getTypescriptDemo(content, demoPath); + + const dirs = path.dirname(demoPath).split(path.sep); + + // Parse TSX + if (script) { + const tmpFile = path.join( + tmpFolder, + `${dirs[dirs.length - 2]}-${path.basename(demoPath).replace(/\..*/, '')}.tsx`, + ); + await fs.writeFile(tmpFile, script, 'utf8'); + } + } + + const child = spawn('npm', ['run', 'tsc']); + + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stderr); + + child.on('exit', async code => { + console.timeEnd('Execution...'); + + if (code) { + console.log(chalk.red('💥 OPS! Seems some tsx demo not pass tsc...')); + } else { + await fs.remove(tmpFolder); + console.log(chalk.green('🤪 All tsx demo passed. Congratulations!')); + } + + process.exit(code); + }); +})(); diff --git a/typings/custom-typings.d.ts b/typings/custom-typings.d.ts index 809a080bfd..c0d2123070 100644 --- a/typings/custom-typings.d.ts +++ b/typings/custom-typings.d.ts @@ -50,8 +50,6 @@ declare module 'rc-steps'; declare module 'rc-switch'; -declare module 'rc-upload'; - declare module '*.json' { const value: any; export const version: string;