Skip to content
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

Optional class properties #5421

Closed
russpowers opened this issue Oct 27, 2015 · 5 comments
Closed

Optional class properties #5421

russpowers opened this issue Oct 27, 2015 · 5 comments
Labels
Duplicate An existing issue was already created

Comments

@russpowers
Copy link

It would be useful to be able to declare optional properties on a class, similar to how it works for interfaces. This would allow more expressive structural subtyping with plain classes:

class Name {
  first: string;
  middle?: string;
  last: string;
}

function printName(name: Name) {
  //...
}

printName({first: "First", last: "Last" });

Technically, this is already possible with the recent change to allow merging interfaces and non-ambient classes:

interface Name {
  middle?: string;
}

class Name { 
  first: string;
  last: string
}

However, it's not very DRY for this use case. Now, you might ask, why not just use an interface and not a class when dealing with plain objects with optional properties? Because interfaces are not real values, which means that they cannot be passed around or be decorated, both of which are often useful.

My motivation for requesting this comes from writing a wrapper library for Immutable.js. I'm trying to create a nice way for library users to declare data items and update them. Here's an abbreviated example of how I would like it to look:

class TodoData {
  @prop text?: string;
  @prop completed?: boolean;
}

class Todo extends TypedMap(TodoData) { }

// todoMap is a typed map representing a Todo
var todo = Todo.create();

// The optional properties allow a nice typed syntax for updating the map
todoMap = todoMap.set({text: "Hello"});

// The @prop decorator was used to run Object.defineProperty on each declared property
console.log(todoMap.text);
@mhegazy
Copy link
Contributor

mhegazy commented Oct 27, 2015

Looks like what you care about is the typing for the get and set methods, rather than really having an optional property on the class. from your example the property will exist. if so, then this looks like #1295, you want to type set as:

interface TypedMap<T> {
    set(name: string, value: T[name]): void;
}

@russpowers
Copy link
Author

Thanks for pointing that out, #1295 is an interesting idea. But it would only handle a simple set/get, right? What about something like a typed deep merge:

someObject.merge({child: {name: "Child" }, optional: false });

Anyways, I think there's a better motivating example -- validation of structurally subtyped data using decorators:

class User {
  @maxLength(50)
  firstName: string;

  @maxLength(50)
  middleName?: string;

  @maxLength(50)
  lastName: string;

  @email
  emailAddress: string;

  @phone
  phone?: string;

  @phone
  fax?: string;
}

function createUser(user: User) {
  // run validations and add to user list
}

createUser({
  firstName: "First",
  lastName: "Last",
  email: "first.last@gmail.com",
  phone: "123-345-4567"
});

This is only possible currently if there are no optional properties in your data, but often that's not the case. Also, if we could somehow get isOptional as a parameter to the decorator, we could use it in the validation as well. We could then have some sort of generic validation/schema checking function for these decorated classes:

function validate<T>(ctor: { new(): T }, data: any): T {
  // validate data and return typed object if successful, throw if not
  // or maybe return a list of errors
}

var untypedUserData: any = fetchUserDataFromWebService();
var typedUser = validate(User, untypedUserData);

@mhegazy
Copy link
Contributor

mhegazy commented Oct 28, 2015

looks like a duplicate of #4889 then.

@mhegazy mhegazy closed this as completed Oct 28, 2015
@mhegazy mhegazy added the Duplicate An existing issue was already created label Oct 28, 2015
@russpowers
Copy link
Author

Yes, the partial types would be perfect for the Immutable.js use case. I don't think they would handle the validation use case, since you don't want everything to be optional.

@CreepGin
Copy link

CreepGin commented Jun 3, 2016

Optional class members is implemented in #8625

@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.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants