Skip to content

strictFunctionTypes prevents an assignment not related to functions #28671

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

Open
the-ress opened this issue Nov 26, 2018 · 2 comments
Open

strictFunctionTypes prevents an assignment not related to functions #28671

the-ress opened this issue Nov 26, 2018 · 2 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@the-ress
Copy link

the-ress commented Nov 26, 2018

TypeScript Version: 3.3.0-dev.20181122

Search Terms:
covariance, contravariance, keyof, interface, class, generic

Code

interface IBase {
    foo: string;
}

interface IDerived extends IBase {
    bar: string;
}

type StringPropertyNames<T> = { [P in keyof T]: T[P] extends string ? P : never }[keyof T]
type StringProperties<T> = Pick<T, StringPropertyNames<T>>

interface Foo<T> {
    readonly Bar: StringProperties<T>;
}

let baseProperties: StringProperties<IBase>
let derivedProperties: StringProperties<IDerived>

let baseInterface: Foo<IBase>
let derivedInterface: Foo<IDerived>

baseProperties = derivedProperties // no error
baseInterface = derivedInterface

tsc test.ts --strictFunctionTypes

Expected behavior:
Compiles without errors.

Actual behavior:

test.ts:23:1 - error TS2322: Type 'Foo<IDerived>' is not assignable to type 'Foo<IBase>'.
  Property 'bar' is missing in type 'IBase' but required in type 'IDerived'.

23 baseInterface = derivedInterface
   ~~~~~~~~~~~~~

  test.ts:6:5
    6     bar: string;
          ~~~
    'bar' is declared here.

Playground Link:

Related Issues:
#24190

The documentation says:

Under --strictFunctionTypes function type parameter positions are checked contravariantly instead of bivariantly.

I couldn't find any information saying it should affect anything else.

@j-oliveras
Copy link
Contributor

Changing interface Foo to a type the error disappear:

type Foo<T> = {
    readonly Bar: StringProperties<T>;
}

@weswigham
Copy link
Member

Mmmm this might be one of those cases where the docs don't quite match reality. While strict function types is meant for toggling measuring variance for functions strictly, the flag actually enables variance probing on all types (when compared with themselves) as an optimization - so when comparing different instances of the same type reference or alias, we can see that StringPropertyNames is actually invariant on T, since our typical assignability rules fall flat when conditional types become involved (to be specific, we're way more conservative with conditional type assignability than is often useful).

@weswigham weswigham added the Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature label Nov 26, 2018
@RyanCavanaugh RyanCavanaugh added the Suggestion An idea for TypeScript label Mar 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants