-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generating declarations for readonly/shallowReadonly ref causes TS4058 error #4701 #3
Comments
版本3.2.19 重现
> [email protected] build
> tsc -p tsconfig.json
index.ts:3:17 - error TS4058: Return type of exported function has or is using name 'RefSymbol' from external module "/workspace/vue-refsymbol-issue/node_modules/@vue/reactivity/dist/reactivity" but cannot be named.
3 export function useCounter () {
~~~~~~~~~~
Found 1 error. 原因以下是出问题的代码, import { ref, readonly } from 'vue'
export function useCounter () {
const count = ref(0)
function increment () {
count.value++
}
return {
count: readonly(count),
increment
}
} 问题就出在返回的 那么由此可以推测问题出在 /**
* Creates a readonly copy of the original object. Note the returned copy is not
* made reactive, but `readonly` can be called on an already reactive object.
*/
export declare function readonly<T extends object>(target: T): DeepReadonly<UnwrapNestedRefs<T>>; 因此我们需要再去看 type Primitive = string | number | boolean | bigint | symbol | undefined | null
type Builtin = Primitive | Function | Date | Error | RegExp
export type DeepReadonly<T> = T extends Builtin
? T
: T extends Map<infer K, infer V>
? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
: T extends ReadonlyMap<infer K, infer V>
? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
: T extends WeakMap<infer K, infer V>
? WeakMap<DeepReadonly<K>, DeepReadonly<V>>
: T extends Set<infer U>
? ReadonlySet<DeepReadonly<U>>
: T extends ReadonlySet<infer U>
? ReadonlySet<DeepReadonly<U>>
: T extends WeakSet<infer U>
? WeakSet<DeepReadonly<U>>
: T extends Promise<infer U>
? Promise<DeepReadonly<U>>
: T extends {}
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: Readonly<T> 于是我们可以尝试去重现这个问题TS Playground type Primitive = string | number | boolean | bigint | symbol | undefined | null
type Builtin = Primitive | Function | Date | Error | RegExp
export type DeepReadonly<T> = T extends Builtin
? T
: T extends {}
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: Readonly<T>
declare const RefSymbol: unique symbol
export interface Ref<T = any> {
value: T
[RefSymbol]: true
}
/*
type test = {
readonly value: number;
readonly [RefSymbol]: true;
}
*/
type test = DeepReadonly<Ref<number>> 因此可以判定问题就出在DeepReadonly没有特殊处理 解决修复只需要增加 type Primitive = string | number | boolean | bigint | symbol | undefined | null
type Builtin = Primitive | Function | Date | Error | RegExp
export type DeepReadonly<T> = T extends Builtin
? T
: T extends Ref<infer U>
//增加Ref类型判断
? Ref<DeepReadonly<U>>
: T extends {}
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: Readonly<T>
declare const RefSymbol: unique symbol
export interface Ref<T = any> {
value: T
[RefSymbol]: true
}
/*
type test = Ref<number>
*/
type test = DeepReadonly<Ref<number>> |
由于在fix issue 1111的 PR里面引入了 [RefSymbol]DeepReadonly把 这个 [RefSymbol]也标记为 readonly了,说明对Ref类型的对象也进行了递归readonly处理。 fix是加入对Ref类型的判断收获1 unique symbol的使用
这个就是和issue1111相关联的, 达到的效果是 [RefSymbol] 在 d.ts里面可见, 但是IDE打点点不出来,而且这个unique symbol只用作标记类型用,对象并不会有这个值。 但是对_shallow属性由于注释里面写@internal,d.ts看不到,但是对象里面存在。 (只让用户看见和自动补齐value) 编译后
可以对比一下有没有[RefSymbol]的效果
没有的情况
收获2 这个DeepReadonly 足够全面的写法对DeepReadonly的实现再复习一下思路。
而且对Map, ReadOnlyMap, WeakMap, Set, ReadOnlySet, WeakSet都进行了判断和处理
另外再加Promise和Ref, 然后对{}就是普通的递归了 |
版本:3.2.19 产生issue实例: import { ref, readonly } from 'vue'
export function useCounter() {
const count = ref(0)
function increment () {
count.value++
}
return {
count: readonly(count),
increment
}
}
首先解读RefSymbol,这是什么?作者代码里没有提到RefSymbol,那我可不可以试着看函数返回对象类型定义 function useCounter(): {
count: {
readonly value: number;
readonly [RefSymbol]: true;
};
increment: () => void;
} 有发现了,这里返回的count是个对象,拥有只读value和[RefSymbol]属性,那此时我觉得我应该看看count声明是ref到底做了什么? export declare interface Ref<T = any> {
value: T;
/**
* Type differentiator only.
* We need this to be in public d.ts but don't want it to show up in IDE
* autocomplete, so we use a private Symbol instead.
*/
[RefSymbol]: true;
/* Excluded from this release type: _shallow */
} 找到[RefSymbol]了,是ref生成时定义的接口类型,那我看看ref初始化方法吧 export function ref(value?: unknown) {
return createRef(value, false)
} function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
} 看到这里,我看出ref对象拥有value和[RefSymbol]属性,那为什么readonly后就没有该属性了? 是不是readonly出了问题,一起看看readonly吧 export declare function readonly<T extends object>(target: T): DeepReadonly<UnwrapNestedRefs<T>>;
DeepReadonly
export declare type DeepReadonly<T> = T extends Builtin
? T : T extends Map<infer K, infer V>
? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends ReadonlyMap<infer K, infer V>
? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>> : T extends WeakMap<infer K, infer V>
? WeakMap<DeepReadonly<K>, DeepReadonly<V>> : T extends Set<infer U>
? ReadonlySet<DeepReadonly<U>> : T extends ReadonlySet<infer U>
? ReadonlySet<DeepReadonly<U>> : T extends WeakSet<infer U>
? WeakSet<DeepReadonly<U>> : T extends Promise<infer U>
? Promise<DeepReadonly<U>> : T extends {}
? {
readonly [K in keyof T]: DeepReadonly<T[K]>;
} : Readonly<T>; DeepReadonly缺少对ref类型的处理,试着根据其他声明类型把ref加上 ? Ref<DeepReadonly<U>> : T extends Ref<infer U> 尝试npm run build试一下
此bug尝试解除,源码其实并没有看的特别懂,还是需要一步步查和扩展思路,通过这个bug和之前的reactive and ref type infer is Wrong #1111 #2,让我对ref对象创建和生成更加了解 ps:看源码时遇到了一行不太理解,不会通过jest去查, function createRef(rawValue: unknown, shallow: boolean) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
} 可知rawValue为0 export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
} r为0的情况下,r && r.__v_isRef === true,这句话应该不成立的 没有时间继续深入看了 记录一下 |
@shuzong 如果是 |
十分感谢,昨晚我也看了一下,参数并不是int类型的0 |
Generating declarations for readonly/shallowReadonly ref causes TS4058 error #4701
为什么要读他
可以学到什么
todo
开始时间
2021-12-13
12月第三周
The text was updated successfully, but these errors were encountered: