Skip to content

[3.5.1] Type 'NonNullable<Partial<Config>[T]>' is not assignable to type 'Config[T]' #31675

Closed

Description

TypeScript Version: 3.5.1, 3.6.0-dev.20190530

Search Terms:

partial nonnullable generic mapped strictNullChecks

Code

interface Config {
  string: string
  // There need to be different types in here for the error to occur
  number: number
}

function getConfigOrDefault<T extends keyof Config>(
  userConfig: Partial<Config>,
  key: T,
  defaultValue: Config[T]
): Config[T] {
  const userValue = userConfig[key] // Partial<Config>[T]
  const explicitAssertion = userConfig[key] as Config[T] | undefined // allowed

  // Partial<Config>[T] - already incorrect in 3.4.5?
  const simpleCheck = userValue ? userValue : defaultValue

  // 3.4.5: Config[T]
  // 3.5.1, 3.6.0-dev.20190530: Config[T] | NonNullable<Partial<Config>[T]>
  const assertedCheck = userValue ? userValue! : defaultValue

  return assertedCheck
}

Expected behavior:

No error

Actual behavior:

Type 'Config[T] | NonNullable<Partial<Config>[T]>' is not assignable to type 'Config[T]'.
  Type 'NonNullable<Partial<Config>[T]>' is not assignable to type 'Config[T]'.
    Type 'Partial<Config>[T]' is not assignable to type 'Config[T]'.
      Type 'Partial<Config>' is not assignable to type 'Config'.
        Types of property 'string' are incompatible.
          Type 'string | undefined' is not assignable to type 'string'.
            Type 'undefined' is not assignable to type 'string'.
              Type 'Partial<Config>[T]' is not assignable to type 'string & number'.
                Type 'Partial<Config>[T]' is not assignable to type 'string'.
                  Type 'string | number' is not assignable to type 'Config[T]'.
                    Type 'string' is not assignable to type 'Config[T]'.
                      Type 'string' is not assignable to type 'string & number'.
                        Type 'string' is not assignable to type 'number'.
                          Type 'NonNullable<Partial<Config>[T]>' is not assignable to type 'string & number'.
                            Type 'Partial<Config>[T]' is not assignable to type 'string & number'.
                              Type 'string | number | undefined' is not assignable to type 'string & number'.
                                Type 'undefined' is not assignable to type 'string & number'.
                                  Type 'undefined' is not assignable to type 'string'.
                                    Type 'Partial<Config>[T]' is not assignable to type 'string'.
                                      Type 'string | number' is not assignable to type 'string & number'.
                                        Type 'string' is not assignable to type 'string & number'.
                                          Type 'string' is not assignable to type 'number'.
                                            Type 'NonNullable<Partial<Config>[T]>' is not assignable to type 'string'.
                                              Type 'Partial<Config>[T]' is not assignable to type 'string'.
                                                Type 'string | number | undefined' is not assignable to type 'string'.
                                                  Type 'undefined' is not assignable to type 'string'.
                                                    Type 'string | number' is not assignable to type 'string'.
                                                      Type 'number' is not assignable to type 'string'.ts(2322)

with strictNullChecks: true

Playground Link:

https://www.typescriptlang.org/play/index.html#src=interface%20Config%20%7B%0D%0A%20%20string%3A%20string%0D%0A%20%20%2F%2F%20There%20need%20to%20be%20different%20types%20in%20here%20for%20the%20error%20to%20occur%0D%0A%20%20number%3A%20number%0D%0A%7D%0D%0A%0D%0Afunction%20getConfigOrDefault%3CT%20extends%20keyof%20Config%3E(%0D%0A%20%20userConfig%3A%20Partial%3CConfig%3E%2C%0D%0A%20%20key%3A%20T%2C%0D%0A%20%20defaultValue%3A%20Config%5BT%5D%0D%0A)%3A%20Config%5BT%5D%20%7B%0D%0A%20%20const%20userValue%20%3D%20userConfig%5Bkey%5D%20%2F%2F%20Partial%3CConfig%3E%5BT%5D%0D%0A%20%20const%20explicitAssertion%20%3D%20userConfig%5Bkey%5D%20as%20Config%5BT%5D%20%7C%20undefined%0D%0A%0D%0A%20%20%2F%2F%20Partial%3CConfig%3E%5BT%5D%20-%20already%20incorrect%20in%203.4.5%3F%0D%0A%20%20const%20simpleCheck%20%3D%20userValue%20%3F%20userValue%20%3A%20defaultValue%0D%0A%0D%0A%20%20%2F%2F%203.4.5%3A%20Config%5BT%5D%0D%0A%20%20%2F%2F%203.5.1%2C%203.6.0-dev.20190530%3A%20Config%5BT%5D%20%7C%20NonNullable%3CPartial%3CConfig%3E%5BT%5D%3E%0D%0A%20%20const%20assertedCheck%20%3D%20userValue%20%3F%20userValue!%20%3A%20defaultValue%0D%0A%0D%0A%20%20return%20assertedCheck%0D%0A%7D%0D%0A

(error does not occur there - which TS version does the playground run on?)

Related Issues:

These issues looked similar but were already reported for earlier versions of TypeScript:

#27456
#30706

Activity

  1. wezleytsai commented on Nov 11, 2019

    @wezleytsai

    My current workaround for this issue:

    interface Config {
      string: string
      // There need to be different types in here for the error to occur
      number: number
    }
    
    // This compiles just fine in 3.7.2
    function getValueOrDefault<K extends keyof T, T>(obj: Partial<T>, key: K, defaultValue: T[K]): T[K] {
        return obj[key] ?? defaultValue;
    }
    
    function getConfigOrDefault<T extends keyof Config>(
      userConfig: Partial<Config>,
      key: T,
      defaultValue: Config[T]
    ): Config[T] {
      // return userConfig[key] ?? defaultValue; // I would expect this to work, as stated above
      return getValueOrDefault(userConfig, key, defaultValue);
    }
  2. 13 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Fix AvailableA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.RescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions