From b772bba5587726e78b20ccb9b61374120bd4b0ae Mon Sep 17 00:00:00 2001 From: Pick Date: Wed, 15 Jul 2020 21:27:21 +0800 Subject: [PATCH] feat(types/reactivity): use `DeepReadonly` type for `readonly` return type (#1462) close #1452 --- .github/contributing.md | 2 +- packages/reactivity/src/reactive.ts | 24 +++++++++++++++++++++++- test-dts/reactivity.test-d.ts | 9 +++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 test-dts/reactivity.test-d.ts diff --git a/.github/contributing.md b/.github/contributing.md index f890f31c..df3efd9a 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -244,7 +244,7 @@ Test coverage is continuously deployed at https://vue-next-coverage.netlify.app/ This project uses [tsd](https://github.com/SamVerschueren/tsd) to test the built definition files (`*.d.ts`). -Type tests are located in the `test-dts` directory. To run the dts tests, run `yarn test-dts`. Note that the type test requires all relevant `*.d.ts` files to be built first (and the script does it for you). Once the `d.ts` files are built and up-to-date, the tests can be re-run by simply running `./node_modules/.bin/tsd`. +Type tests are located in the `test-dts` directory. To run the dts tests, run `yarn test-dts`. Note that the type test requires all relevant `*.d.ts` files to be built first (and the script does it for you). Once the `d.ts` files are built and up-to-date, the tests can be re-run by simply running `yarn test-dts`. ## Financial Contribution diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 0dfec8a9..1f01c393 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -72,9 +72,31 @@ export function shallowReactive(target: T): T { ) } +type Primitive = string | number | boolean | bigint | symbol | undefined | null +type Builtin = Primitive | Function | Date | Error | RegExp +type DeepReadonly = T extends Builtin + ? T + : T extends Map + ? ReadonlyMap, DeepReadonly> + : T extends ReadonlyMap + ? ReadonlyMap, DeepReadonly> + : T extends WeakMap + ? WeakMap, DeepReadonly> + : T extends Set + ? ReadonlySet> + : T extends ReadonlySet + ? ReadonlySet> + : T extends WeakSet + ? WeakSet> + : T extends Promise + ? Promise> + : T extends {} + ? { readonly [K in keyof T]: DeepReadonly } + : Readonly + export function readonly( target: T -): Readonly> { +): DeepReadonly> { return createReactiveObject( target, true, diff --git a/test-dts/reactivity.test-d.ts b/test-dts/reactivity.test-d.ts new file mode 100644 index 00000000..edccd4fa --- /dev/null +++ b/test-dts/reactivity.test-d.ts @@ -0,0 +1,9 @@ +import { readonly, describe, expectError } from './index' + +describe('should support DeepReadonly', () => { + const r = readonly({ obj: { k: 'v' } }) + // @ts-expect-error + expectError((r.obj = {})) + // @ts-expect-error + expectError((r.obj.k = 'x')) +})