After updating typescript from 2.3 to 2.6, I see this error in several of my typings. What does it actually mean ? Can you give me an example ?
EDIT:
I understand that this message indicates erroneous interface extension/implementation. I'm more interesting in the meaning of no properties in common
. The suggested question shows an example of a class that implements an interface. What I've seen is an interface extending another interface and changing type of one of the properties. What does it have to do with the message ?
TypeScript 2.4 introduced stronger checking of weak types, e.g. an interface where all properties are optional.
Suppose we have two weak types with different properties:
interface A {
a?: string;
}
interface B {
b?: string;
}
let x: A = {};
let y: B = {};
Notice that both x
and y
are empty objects that satisfy their respective weak types A
and B
.
Now, is it a mistake to assign an A
to a B
?
y = x;
TypeScript 2.4+ says yes, this is a mistake:
Type 'A' has no properties in common with type 'B'.
This is a simplified example; your typings file is certainly more complex but I hope this illustrates the intent of the error. If you post some code, we can dig into it further.
If TypeScript's weak type checking is being over-cautious in your case, there are workarounds such as casting or using an index signature:
https://blog.mariusschulz.com/2017/12/01/typescript-2-4-weak-type-detection
To add to the previous answer. If you run into the same issue as I did and the [key: string]: unknown
property does not solve the error for you, you could also just extend Object
in you pure optional interface. Since the Object interface has non optional properties this removes Weak Type checking but in turn requires your value to conform to the now expanded interface, which is not always the case.
So for example in my case, where I needed this for a react hook, this would mean:
// Added extends Object to get around Weak Type checking
interface DestroyableInstance extends Object {
destroy?(): void;
}
const useInstance = <T extends DestroyableInstance>(creator: { new(): T }): T => {
const [instance] = useState(() => new creator());
useEffect(() => {
// This is not guaranteed to be executed
// There is a hidden second cycle after a real render
// which will not execute the useEffect cleanup
return () => {
if (instance.destroy)
instance.destroy();
}
}, [instance]);
return instance;
}
class Drawer {
constructor() {
}
// destroy is now optional and there is no error when used in the React hook
}
const ExampleComponent = () => {
// Without the extends Object you would get an error here
// since Drawer would have no overlap.
const instance = useInstance(Drawer);
// You now you can use the instance
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With