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 — Static types for dynamically named properties by ahejlsberg · Pull Request #11929 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented Oct 28, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR adds new typing constructs that enable static validation of code involving dynamic property names and properties selected by such dynamic names. For example, in JavaScript it is fairly common to have APIs that expect property names as parameters, but so far it hasn't been possible to express the type relationships that occur in those APIs. The PR also improves error messages related to missing properties and/or index signatures.

The PR is inspired by #1295 and #10425 and the discussions in those issues. The PR implements two new type constructs:

  • Index type queries of the form keyof T, where T is some type.
  • Indexed access types of the form T[K], where T is some type and K is a type that is assignable to keyof T (or assignable to number if T contains a numeric index signature).

An index type query keyof T yields the type of permitted property names for T. A keyof T type is considered a subtype of string. When T is not a type parameter, keyof T is resolved as follows:

  • If T has no apparent string index signature, keyof T is a type of the form "p1" | "p2" | ... | "pX", where the string literals represent the names of the public properties of T. If T has no public properties, keyof T is the type never.
  • If T has an apparent string index signature, keyof T is the type string.

Note that keyof T ignores numeric index signatures. To properly account for those we would need a numericstring type to represent strings contain numeric representations.

An indexed access type T[K] requires K to be a type that is assignable to keyof T (or assignable to number if T contains a numeric index signature) and yields the type of the property or properties in T selected by K. T[K] permits K to be a type parameter, in which case K must be constrained to a type that is assignable to keyof T. Otherwise, when K is not a type parameter, T[K] is resolved as follows:

  • If K is a union type K1 | K2 | ... | Kn, T[K] is equivalent to T[K1] | T[K2] | ... | T[Kn].
  • If K is a string literal type, numeric literal type, or enum literal type, and T contains a public property with the name given by that literal type, T[K] is the type of that property.
  • If K is a type assignable to number and T contains a numeric index signature, T[K] is the type of that numeric index signature.
  • If K is a type assignable to string and T contains a string index signature, T[K] is the type of that string index signature.

Some examples:

interface Thing {
    name: string;
    width: number;
    height: number;
    inStock: boolean;
}

type K1 = keyof Thing;  // "name" | "width" | "height" | "inStock"
type K2 = keyof Thing[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Thing };  // string

type P1 = Thing["name"];  // string
type P2 = Thing["width" | "height"];  // number
type P3 = Thing["name" | "inStock"];  // string | boolean
type P4 = string["charAt"];  // (pos: number) => string
type P5 = string[]["push"];  // (...items: string[]) => number
type P6 = string[][0];  // string

An indexed access type T[K] permits K to be a type parameter that is constrained to keyof T. This makes it possible to do parametric abstraction over property access:

function getProperty<T, K extends keyof T>(obj: T, key: K) {
    return obj[key];  // Inferred type is T[K]
}

function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
    obj[key] = value;
}

function f1(thing: Thing, propName: "name" | "width") {
    let name = getProperty(thing, "name");  // Ok, type string
    let size = getProperty(thing, "size");  // Error, no property named "size"
    setProperty(thing, "width", 42);  // Ok
    setProperty(thing, "color", "blue");  // Error, no property named "color"
    let nameOrWidth = getProperty(thing, propName);  // Ok, type string | number
}

function f2(tuple: [string, number, Thing]) {
    let length = getProperty(tuple, "length");  // Ok, type number
    const TWO = "2";
    let t0 = getProperty(tuple, "0");  // Ok, type string
    let t1 = getProperty(tuple, "1");  // Ok, type number
    let t2 = getProperty(tuple, TWO);  // Ok, type Thing
}

class Component<PropType> {
    props: PropType;
    getProperty<K extends keyof PropType>(key: K) {
        return this.props[key];
    }
    setProperty<K extends keyof PropType>(key: K, value: PropType[K]) {
        this.props[key] = value;
    }
}

function f3(component: Component<Thing>) {
    let width = component.getProperty("width");  // Ok, type number
    component.setProperty("name", "test");  // Ok
}

function pluck<T, K extends keyof T>(array: T[], key: K) {
    return array.map(x => x[key]);
}

function f4(things: Thing[]) {
    let names = pluck(things, "name");  // string[]
    let widths = pluck(things, "width");  // number[]
}

Note: This description has been edited to reflect the changes implemented in #12425.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

aluanhaddad, alitaheri, gcnew, tinganho, weswigham, svieira, HerringtonDarkholme, yortus, zpdDG4gta8XKpMCd, gulshan, and 55 more reacted with thumbs up emoji jwbay, aluanhaddad, alitaheri, svieira, HerringtonDarkholme, zpdDG4gta8XKpMCd, alinhle, mpawelski, niieani, vilicvane, and 21 more reacted with hooray emoji alitaheri, HerringtonDarkholme, zpdDG4gta8XKpMCd, alinhle, ceymard, remojansen, wclr, blakeembrey, aluanhaddad, goodmind, and 23 more reacted with heart emoji
All reactions
  • 👍 65 reactions
  • 🎉 31 reactions
  • ❤️ 33 reactions
Anders Hejlsberg (ahejlsberg) added 7 commits October 24, 2016 15:24
@ahejlsberg
Initial implementation of 'keyof T' type operator
ad88109
@ahejlsberg
Introduce PropertyNameType
07478aa
@ahejlsberg
Initial implementation of 'T[K]' property access types
c21592e
@ahejlsberg
Support parametric property access expressions + some renaming
e7cfbfe
@ahejlsberg
Consider index signatures in type produced by 'keyof T'
4b50ef3
@ahejlsberg
Refactor getIndexedAccessType to be reusable from checkIndexedAccess
ece1f19
@ahejlsberg
Minor fixes
8d87971
@msftclas Microsoft Contribution License Agreements (msftclas) added the cla-not-required label Oct 28, 2016
@weswigham

Wesley Wigham (weswigham) commented Oct 29, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Anders Hejlsberg (@ahejlsberg) Does this also adjust the logic for handling actual index expressions? For example,

interface Foo {
  a: 0
  b: 1
}
var x: "a" | "b";
var y: Foo;
var z = y[x]; // Is this Foo["a" | "b"] or 0 | 1 (rather than relying on a nonexistant index signature for the type or being any)?

Or is actual indexing unchanged? IMO, it would make the most sense if the typespace indexing operator and the valuespace one affected type flow in the same way.

This was the last half-feature/concern I had identified in the original issue.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Oct 29, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Wesley Wigham (@weswigham) The operation y[x] will produce type 0 | 1 once I do the remaining work to unify indexing in the expression world with indexing in the type world.

EDIT: The remaining unification is done and y[x] now produces type 0 | 1.

BTW, there is an interesting issue around reading vs. writing when the index type is not a unit type. Technically, it is only safe to union together the resulting values when you're reading. For writing, the only safe construct would be an intersection, but that is rarely useful. So, we're planning to make writing an error when the index type is not a unit type:

interface Foo { a: 0, b: 1 }

function f1(foo: Foo, x: "a" | "b") {
    const c = foo[x];  // Ok, type 0 | 1
    foo[x] = c;  // Error, absent index signatures an index expresion must be of a unit type
}

However, in the parametric case we make no distinction between keyof T types used for reading vs. writing, so you can "cheat":

function setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {
    obj[key] = value;
}

function f2(foo: Foo, x: "a" | "b") {
    const c = foo[x];  // Ok, type 0 | 1
    setProperty(foo, x, c);  // Ok
}

It actually seems fairly reasonable to allow this. Really, there are three distinct possibilities:

  • The operation is known to never be safe. We always error in such cases.
  • The operation could be safe provided index and value match appropriately. We permit that only in generic cases.
  • The operation is known to always be safe. We never error in such cases.

The alternative is to have distinct safe for reading, safe for writing, and safe for reading and writing versions of keyof T. That seems like overkill, or at best an orthogonal issue we should consider if we ever decide to go all in on variance annotations.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Oct 30, 2016
element.style[key] = value throws implicit any error #11914
Closed
@HerringtonDarkholme Herrington Darkholme (HerringtonDarkholme) mentioned this pull request Oct 30, 2016
watch scope HerringtonDarkholme/av-ts#5
Closed
Anders Hejlsberg (ahejlsberg) added 6 commits October 30, 2016 16:01
@ahejlsberg
Improved error messages for invalid assignments to identifiers
5515dce
@ahejlsberg
Accept new baselines
550be9c
@ahejlsberg
Improved error messages for invalid assignments to properties
6c20533
@ahejlsberg
Accept new baselines
88961cd
@ahejlsberg
Improve more error messages
2f34f7c
@ahejlsberg
Accept new baselines
f293744
@tinganho Tingan Ho (tinganho) mentioned this pull request Oct 31, 2016
Dynamic Super Types #11967
Open
Anders Hejlsberg (ahejlsberg) added 3 commits October 31, 2016 15:28
@ahejlsberg
Unify checking of indexed access expressions and indexed access types
f9e2085
@ahejlsberg
Accept new baselines
03f8403
@ahejlsberg
Accept additional baselines
8d9356f
@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Oct 31, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Latest set of commits unify type checking of indexed access expressions and indexed access types. Also, improved error messages for a number of errors related to property/element access and constant/read-only checking.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg
Merge branch 'master' into keyoftypes
6b28d21
# Conflicts:
#	src/compiler/diagnosticMessages.json
mhegazy
Mohamed Hegazy (mhegazy) reviewed Nov 1, 2016
View reviewed changes
Comment thread src/compiler/types.ts
/* @internal */
resolvedIndexType: IndexType;
/* @internal */
resolvedIndexedAccessTypes: IndexedAccessType[];

@mhegazy Mohamed Hegazy (mhegazy) Nov 1, 2016

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why array instead of map? the array is going to be sparse if indexed with type id.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) Nov 1, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it will be sparse, in the same way that our nodeLinks and symbolLinks arrays are sparse. I believe this performs better than a map.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
mhegazy
Mohamed Hegazy (mhegazy) reviewed Nov 1, 2016
View reviewed changes
Comment thread src/compiler/checker.ts Outdated
return indexedAccessTypes[objectType.id] || (indexedAccessTypes[objectType.id] = createIndexedAccessType(objectType, indexType));
}

function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {

@mhegazy Mohamed Hegazy (mhegazy) Nov 1, 2016

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not this be getPropertyTypeForIndexedType or getPropertyTypeForIndexAccess since it operates on the indexed type rather than the index type.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) Nov 1, 2016

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it operates both on the indexed type and the index type. So, technically it should be getPropertyTypeForIndexedTypeIndexedByIndexType. 😃 Honestly, not sure what would be a good name.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ahejlsberg
Improve unification by moving more logic to getIndexedAccessType
41c2054
mhegazy
Mohamed Hegazy (mhegazy) reviewed Nov 1, 2016
View reviewed changes
Comment thread src/compiler/diagnosticMessages.json
"code": 7016
},
"Index signature of object type implicitly has an 'any' type.": {
"Element implicitly has an 'any' type because type '{0}' has no index signature.": {

@mhegazy Mohamed Hegazy (mhegazy) Nov 1, 2016

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 this is much better now!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

styfle, rictic, and Brooooooklyn reacted with thumbs up emoji
All reactions
  • 👍 3 reactions
mhegazy
Mohamed Hegazy (mhegazy) reviewed Nov 1, 2016
View reviewed changes
Comment thread src/compiler/checker.ts Outdated
error(indexNode, Diagnostics.Property_0_does_not_exist_on_type_1, (<LiteralType>indexType).text, typeToString(objectType));
}
else if (indexType.flags & (TypeFlags.String | TypeFlags.Number)) {
error(accessNode, Diagnostics.Type_0_has_no_matching_index_signature_for_type_1, typeToString(objectType), typeToString(indexType));

@mhegazy Mohamed Hegazy (mhegazy) Nov 1, 2016

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i do not see any tests for this scenario.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) Nov 1, 2016

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I still haven't added tests.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
mhegazy
Mohamed Hegazy (mhegazy) reviewed Nov 1, 2016
View reviewed changes

@mhegazy Mohamed Hegazy (mhegazy) left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see any tests for keyof and/or T[K]. also please include some declaration emit tests.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@HerringtonDarkholme Herrington Darkholme (HerringtonDarkholme) mentioned this pull request Nov 18, 2016
Feature request: represent Function via generic type parameterized by its return/parameter/this type #12342
Closed
@HerringtonDarkholme

Herrington Darkholme (HerringtonDarkholme) commented Nov 18, 2016

Copy link
Copy Markdown
Contributor

I wonder whether index access type works with constrained generic parameter. For example, only the last alias of the following three is resolved to number.

type A<T extends {[K in "test"]: any}> = T["test"]
type B<T extends {test: any}> = T["test"]
type C<T extends {test: any}, K extends keyof T> = T[K]

type A1 = A<{test: number}>
type B1 = B<{test: number}>
type C1 = C<{test: number}, "test">

Is this intended?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Nov 19, 2016

Copy link
Copy Markdown
Member Author

Herrington Darkholme (@HerringtonDarkholme) In an indexed access T["test"], where T is a type parameter, we eagerly resolve the type based on the constraint of T. So if T has the constraint { test: any }, we'll eagerly resolve to type any. We only defer the operation when the index type is also a type parameter. Deferring T["test"] would have a lot of downstream effects on existing code because it changes every access to a property of this within a class to be a deferred generic type. It might be possible to do it at some point, but it is not a short-term option.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Nov 20, 2016
[feature request] consistent index access type for this type #12349
Closed
feat request: allow preserving keys (+ types by key) to map over objects #12393
Closed
@canufeel Petr Kosikhin (canufeel) mentioned this pull request Nov 21, 2016
Feature request: Multiple level deep Static types for dynamically named properties. #12407
Closed
@fula2013

fula2013 commented Nov 23, 2016

Copy link
Copy Markdown

Anders Hejlsberg (@ahejlsberg) what about support for regex check type? like this:
type SomeTel = match of /^\d{4}-\d{6}$/; var tel: SomeTel = '0768-888888'; //is ok

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Quramy Yosuke Kurami (Quramy) mentioned this pull request Nov 24, 2016
Add "keyof" to reserved words leafgarland/typescript-vim#102
Merged
@HerringtonDarkholme Herrington Darkholme (HerringtonDarkholme) mentioned this pull request Nov 26, 2016
no mapping for this #12507
Closed
@wstaelens wstaelens mentioned this pull request Nov 28, 2016
TypeScript 2.1: use keyof wstaelens/TypeScript-Summernote#1
Open
@gustavderdrache gustavderdrache mentioned this pull request Dec 1, 2016
[types-2.0] D3 strictNullChecks Batch 1 DefinitelyTyped/DefinitelyTyped#12858
Merged
7 of 11 tasks
@CodySchaaf

Cody Schaaf (CodySchaaf) commented Dec 10, 2016

Copy link
Copy Markdown

Is there no way to make private members accessible? Would be nice if you could do something similar to the readonly transformation.

My Specific example is when transforming the current class to the IOnChangesObject in angular.

type IOnChangesObject<T> = {[P in keyof T]: ng.IChangesObject<T[P]>}

$onChanges(changesObj: IOnChangesObject<Ctrl>) { 
//both private and public attributes should work on changesObj
}

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@kayhorrors Kay (kayhorrors) mentioned this pull request Dec 11, 2016
Use keyof to improve type safety DefinitelyTyped/DefinitelyTyped#13254
Closed
6 tasks done
@nahakyuu

nahakyuu (nahakyuu) commented Dec 20, 2016

Copy link
Copy Markdown
type Foo<T> = T & {
    Test: () => void;
}
type Foo1<T> = keyof Foo<T>;

type Foo2 = Foo1<{ prop: string }>;

type Foo2 = "Test"

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nevir

Ian MacLeod (nevir) commented Dec 20, 2016

Copy link
Copy Markdown

Should this also work for object literals? I would have expected the following to also work:

const thing = {
  a: 'foo',
  b: 'bar',
};

// Expected: "a" | "b"
// Actual: Cannot find name 'thing'
type thingKey = keyof thing;
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@gcnew

Marin Marinov (gcnew) commented Dec 20, 2016 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Ian MacLeod (@nevir) Use typeof to get the type of thing

type thingKey = keyof typeof thing;
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nevir

Ian MacLeod (nevir) commented Dec 20, 2016

Copy link
Copy Markdown

Ah! Thanks!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Artazor

Anatoly Ressin (Artazor) commented Mar 14, 2017 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

just want to share it here:
(Advanced usage of mapped types and static types for dynamically named properties)

//////////////////////////////////  USAGE /////////////////////////////////

var sequelize = new Sequelize();
var Users = sequelize.define("users", {
    firstName: STRING,
    lastName: CHAR(123),
    age: INTEGER,
    visits: { type: INTEGER, length: 4}
});

var u = Users.create({age: 22}); // only valid fields/types allowed 
u.firstName = "John"; // types are checked at compile time
u.lastName = "Doe"
u.visits = 123;


///////////////////////////////// DECLARATIONS /////////////////////////////


interface ABSTRACT_STATIC<T> {
    prototype: ABSTRACT<string, T>;
}
interface ABSTRACT_BASE<T> {
    stringify(value: T, options): string;
    validate(value: T);
}

interface ABSTRACT<Key, T> extends ABSTRACT_BASE<T> { 
    key: Key;
    dialectTypes: string;
    toSql: string;
    warn(link: string, text);
}

interface STRING_OPTIONS { length?: number, binary?: boolean }
interface STRING<Key> extends ABSTRACT<Key, string> {
    readonly BINARY: this
}
interface STRING_STATIC<Key, T extends STRING<Key>> extends ABSTRACT_STATIC<string> {
    new(length?: number, binary?: boolean): T;
    new(options: STRING_OPTIONS): T;
    (length?: number, binary?: boolean): T;
    (options: STRING_OPTIONS): T;
}
declare const STRING: STRING_STATIC<"STRING", STRING<"STRING">>;

interface CHAR extends STRING<"CHAR"> {}
interface CHAR_STATIC extends STRING_STATIC<"CHAR", CHAR> {}
declare const CHAR: CHAR_STATIC;

interface NUMBER_OPTIONS {
    length?: number,
    zerofill?: boolean,
    decimals?: number,
    precision?: number,
    scale?: number,
    unsigned?: boolean
}
interface NUMBER<Key> extends ABSTRACT<Key, number> {
    readonly UNSIGNED: this
    readonly ZEROFILL: this
}
interface NUMBER_STATIC<Key, T extends NUMBER<Key>> extends ABSTRACT_STATIC<number> {
    new(options: NUMBER_OPTIONS): T;
    (options: NUMBER_OPTIONS): T;
}
declare const NUMBER: NUMBER_STATIC<"NUMBER", NUMBER<"NUMBER">>;

interface INTEGER extends NUMBER<"INTEGER"> {}
interface INTEGER_STATIC extends NUMBER_STATIC<"INTEGER", INTEGER> {
    new(): INTEGER;
    (): INTEGER;
    new(length: number): INTEGER;
    (length: number): INTEGER;
}
declare const INTEGER: INTEGER_STATIC;
interface OPTIONS<T> { type: ABSTRACT_STATIC<T> }

interface STRING_OPTIONS_TYPE extends OPTIONS<string>, STRING_OPTIONS { }
interface NUMBER_OPTIONS_TYPE extends OPTIONS<number>, NUMBER_OPTIONS { }

type FIELD<T> = ABSTRACT_STATIC<T>
    | OPTIONS<T> & (
        STRING_OPTIONS_TYPE |
        NUMBER_OPTIONS_TYPE
        )
    | ABSTRACT_BASE<T> 

type INIT<T> = {[P in keyof T]?:T[P]}

declare class Factory<T> {
    create(initial?: INIT<T>): T
}

declare class Sequelize {
    define<T>(tableName: string, fields: {[P in keyof T]: FIELD<T[P]>}):Factory<T> 
}
frankwallis, pablobirukov, and bradstewart reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mhegazy Mohamed Hegazy (mhegazy) mentioned this pull request Apr 27, 2017
Proposal - Nested property access notation for types #10693
Closed
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request May 30, 2017
Resulting type of the object literal #16130
Closed
@olegdunkan olegdunkan mentioned this pull request Jun 16, 2017
Keyof doesn't see all apparent members #16578
Closed
@weswigham Wesley Wigham (weswigham) mentioned this pull request Jul 24, 2017
Cannot use this to index private or protected properties #17362
Closed
@olegdunkan olegdunkan mentioned this pull request Aug 19, 2017
Index access type from intersection #17929
Closed
@CKGrafico Quique Fdez Guerra (CKGrafico) mentioned this pull request Aug 30, 2017
Keyof CKGrafico/Why-TypeScript#1
Open
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Oct 24, 2017
Discussion about typeof navigation #19441
Closed
@mzp Hiro Mizuno (mzp) mentioned this pull request Dec 3, 2017
Add supports for index type query and indexed access type sjrd/scala-js-ts-importer#52
Merged
@yortus Troy Gerwien (yortus) mentioned this pull request Dec 15, 2017
Consider adding symbolof type operator, like keyof but for unique symbol properties #20721
Closed
This was referenced Feb 17, 2018
RequiredProps<T>: Unexpected result when T = {} #21988
Closed
T[keyof T] should be never for T={} #22042
Closed
@microsoft Microsoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

1 more reviewer
@mhegazy Mohamed Hegazy (mhegazy) mhegazy approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

20 participants

@ahejlsberg @weswigham @ThomasMichon @mhegazy @jods4 @dasa @RobertoMalatesta @pelotom @zpdDG4gta8XKpMCd @wclr @PyroVortex @mohsen1 @pleerock @HerringtonDarkholme @fula2013 @CodySchaaf @nahakyuu @nevir @gcnew @Artazor
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.