#Bug with interfaces?

36 messages · Page 1 of 1 (latest)

toxic shell
#

Hello, TS team,

interface MyInterface {
    optionalProp?: string;
}

class MyClass implements MyInterface {
    // TypeScript will throw an error here, because MyClass has no matching properties
}

Why does ts(2559) error generate based on this code? If optionalProp is optional in MyInterface, why does the class have to define it?

sour current
#

@toxic shell I'm not seeing it happening on the playground -

torpid rampartBOT
#
retsam19#0

Preview:```ts
interface MyInterface {
optionalProp?: string
}

class MyClass implements MyInterface {
// TypeScript will throw an error here, because MyClass has no matching properties
}```

sour current
#

What version of TS are you using?

#

Hello, TS team
(Also FYI, this is a community discord, the members here generally aren't the TS team)

toxic shell
#

Ah cool! Maybe I'm on an old version: 4.5.5

sour current
#

Hmm, the playground has a version dropdown and it still works on that version - maybe there's something more complex in your actual case?

toxic shell
torpid rampartBOT
#

@toxic shell Here's a shortened URL of your playground link! You can remove the full link from your message.

16041374#0

Preview:```ts
interface OptionalInterface {
optionalProp?: string
}

class ImplClass implements OptionalInterface {
private prop: string = ""
}```

toxic shell
#

Type 'ImplClass' has no properties in common with type 'OptionalInterface'.(2559)

sour current
#

Yeah, I think TS is flagging that because it looks like it could be a mistake - implements OptionalInterface really isn't doing very much there.

#

The only thing that does is that TS will raise an error if you declared optionalProp with some other type, I guess.

toxic shell
#

Seems like a bug in TSC to me

sour current
#

I don't really think so

toxic shell
#

ImplClass is adhering to the "contract" by OptionalInterface. Why does it throw an error?

sour current
#

Because it looks like a likely error

#

TS sometimes flags things that 'look like mistakes' even if they're potentially intentional.

toxic shell
#

Ahh okay. My understanding was that TSC would only flag errors for actual errors, not potential errors

sour current
#

A lot of the distinction of what's an 'actual error' is kinda blurry.

#

If TS only tried to catch things that blew up at runtime, it'd be much looser than it actually is.

#

e.g.

#
type Obj = { foo: string };

function foo(obj: Obj) {
  console.log(obj.fooo) // is this an 'actual error'?  Doesn't crash at runtime and maybe I want to check for an undeclared property
}
toxic shell
#

That seems like an error to me

#

I don't see how the example above with the OptionalInterface could cause an error

sour current
#

It's not a runtime error though

#

It's not always about "can cause an error" (console.log(obj.fooo) doesn't cause an error) - it's about catching mistakes: obj.fooo is almost certainly a mistake.

#

(But not always - people do run into cases where they want to check for properties not declared in the type)

toxic shell
#

Ok cool. So assuming TSC is designed with the intention of catching mistakes. How is the OptionalInterface example catching a mistake?

sour current
#

It's "weak type detection" - when two types are completely unrelated, you might not acutally be assigning an object to the type you think you are

toxic shell
#

Cool! That makes sense to me. So the error is not about incompatibility, but rather, sort of like a "heads up" or warning that the behavior may not be as I intended

sour current
#

Yeah - and you can make it clear that you're actually doing it on purpose by adding the optionalProp?: string to the class explicitly.

toxic shell
#

Still doesn't seem consistent that adding private prop: string = '' will change the error

sour current
#

Assigning an empty type to an object without properties is a normal thing to do - yeah it's kinda weird in classes, but it's the equivalent of:

const obj = {};
const options: OptionsTypeWithoutMandatoryProperties = obj;
torpid rampartBOT
#
type OptionsTypeWithoutMandatoryProperties = {
  foo?: string;
}

// No error (and would be weird if it did)
const obj1 = {  };
const options1: OptionsTypeWithoutMandatoryProperties = obj1;

// Error (and yes, probably a mistake)
const obj2 = { fooo: 'string' };
const options2: OptionsTypeWithoutMandatoryProperties = obj2;
//    ^^^^^^^^
// Type '{ fooo: string; }' has no properties in common with type 'OptionsTypeWithoutMandatoryProperties'.
sour current
#

To your specific case, I think if prop were a typo of an actual prop in OptionalInterface this would be a very useful error.