镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Keyof doesn't see all apparent members  #16578

Description

@olegdunkan

TypeScript Version: playground
Code

function check<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}
function fn(){}

var f1: Function = fn;
var f2: {():void} = fn;

check(f1, "bind");  //ok
check(f2, "bind"); //error
f2.bind; //ok

Expected behavior:

An index type query keyof T yields the type of permitted property names for T
I expected that "bind" is permitted (as I assume, public and in some cases protected) and apparent members of type {():void}

Form spec:
The apparent members of an object type T are the combination of the following:

  • The declared and/or inherited members of T.
  • The properties of the global interface type 'Object' that aren't hidden by properties with the same name in T.
  • If T has one or more call or construct signatures, the properties of the global interface type 'Function' that aren't hidden by properties with the same name in T.

Actual behavior:
Error.
If it by design I am with great pleasure would like to know what is permitted property names?

Activity

  1. ahejlsberg commented on Jun 16, 2017

    @ahejlsberg
    Member

    This is by design. The keyof operator only considers the declared or inherited properties of a type, not those that come from its apparent type.

  2. olegdunkan commented on Jun 16, 2017

    @olegdunkan
    Author

    Anders Hejlsberg (@ahejlsberg) ok, thanks.

    Would you mind if ask a question.
    Spec doesn't define a notion of the apparent type, only apparent members .

    From spec:
    The apparent members of the primitive type String and all string literal types are the apparent members of the global interface type 'String'

    I can assume from spec that the global interface String is a apparent type if so then the global interface type 'Function' is also a apparent type.

    For global interface String it works, but for the global Function doesn't !!!

    check("", "atChar");  //ok

    The question is what is the apparent type, what is a difference between String and Function and more interesting what is a motivation to differ (Number, String and Boolean) and (Object, Function) global interfaces in the context of the keyof type query?

  3. olegdunkan commented on Jun 17, 2017

    @olegdunkan
    Author

    I have made some investigations.
    From tsc code follows that the apparent type of type T is {} except:
    for string is global interface String,
    for number is global interface Number,
    for boolean is global interface Boolean,
    for type parameter is constraint, if any,
    ...

    function getApparentType(type: Type): Type {
                const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(type) || emptyObjectType : type;
                return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
                    t.flags & TypeFlags.StringLike ? globalStringType :
                    t.flags & TypeFlags.NumberLike ? globalNumberType :
                    t.flags & TypeFlags.BooleanLike ? globalBooleanType :
                    t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) :
                    t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
                    t;
            }

    The motivation to differ (Number, String and Boolean) and (Object, Function) is probably to prevent enumerating of native (intrinsic) properties of Object and Function for user types.

  4. locked and limited conversation to collaborators on Jun 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    By DesignDeprecated - use "Working as Intended" or "Design Limitation" instead

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions