GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Keyof doesn't see all apparent members · Issue #16578 · microsoft/TypeScript

Keyof doesn't see all apparent members  #16578

New issue
Copy link
New issue
Copy link
Closed
Closed
Keyof doesn't see all apparent members #16578
Copy link
Labels
By DesignDeprecated - use "Working as Intended" or "Design Limitation" insteadDeprecated - use "Working as Intended" or "Design Limitation" instead

Description

@olegdunkan
olegdunkan
opened on Jun 16, 2017
Issue body actions

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
    Anders Hejlsberg (ahejlsberg)
    on Jun 16, 2017
    Member
    More actions

    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. Anders Hejlsberg (ahejlsberg)
    added
    By DesignDeprecated - use "Working as Intended" or "Design Limitation" insteadDeprecated - use "Working as Intended" or "Design Limitation" instead
    on Jun 16, 2017
  3. olegdunkan commented on Jun 16, 2017

    @olegdunkan
    olegdunkan
    on Jun 16, 2017
    Author
    More actions

    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?

  4. olegdunkan commented on Jun 17, 2017

    @olegdunkan
    olegdunkan
    on Jun 17, 2017
    Author
    More actions

    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.

  5. olegdunkan
    closed this as completedon Jun 17, 2017
  6. microsoft
    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" insteadDeprecated - 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

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.