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

No way to declare setter/getter only in interfaces #10196

Closed
mindarelus opened this issue Aug 7, 2016 · 7 comments
Closed

No way to declare setter/getter only in interfaces #10196

mindarelus opened this issue Aug 7, 2016 · 7 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@mindarelus
Copy link

export interface ITimer {
get isRunning():boolean;
start():void;
stop():void;
reset():void;
}

Why is this not working? This is the most logical thing anyone would expect. The value of the isRunning property should be changed, only inside the class instances. Otherwise anyone could change it outside, which is not good.

@SimonMeskens
Copy link

Use the readonly keyword instead of the get keyword:

export interface ITimer {
    readonly isRunning: boolean;
    start(): void;
    stop(): void;
    reset(): void;
}

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Aug 7, 2016
@ahejlsberg
Copy link
Member

Interfaces make no distinction between regular properties and accessor properties--it's an implementation detail left up to the implementer of the interface. As suggested above, use the readonly keyword to get the effect of a property that has only a get accessor.

@mindarelus
Copy link
Author

Thanks.. I guess I'll have to get used to write "readonly" :)

@dungdm93
Copy link

dungdm93 commented Oct 27, 2016

@ahejlsberg
using readonly this case is fine. But it make people so confused.
readonly keyword normally indicate un-reassignable property. But in the interface, it act as a getter declaration :(
#11578

Another bad case is implement readonly as computed property:

interface IPerson {
   readonly fullName: string;
}

class Person {
    public firstName: string;
    public lastName: string;

    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
}

let p: Person = new Person("Bruce", "Wayne");
alert(p.fullName);   // Bruce Wayne

p.firstName = "Clark";
p.lastName = "Kent";
alert(p.fullName);   // Clark Kent

From my aspect, allow getter/setter declared in interface make more sense:

interface IPerson {
   get fullName(): string;
}

@SimonMeskens
Copy link

@dungdm93 But it is not reassignable, so it makes sense?

@andredewaard
Copy link

andredewaard commented Jun 6, 2018

I'm trying to get the same working but i get an error:

Argument of type '{ ID: number; firstName: string; lastName: string; }' is not assignable to parameter of type 'IUser | undefined'.
  Type '{ ID: number; firstName: string; lastName: string; }' is not assignable to type 'IUser'.
    Property 'getRole' is missing in type '{ ID: number; firstName: string; lastName: string; }'.

What i try to do:

import { UserRoles } from '@/enums/userRoles';

interface IUser {
  ID?: number | null;
  firstName?: string;
  lastName?: string;
  role?: UserRoles;
  readonly getRole: string;
  readonly getFullName: string;
}

class User implements IUser {

  public ID: number | null = null;
  public firstName: string = '';
  public lastName: string = '';
  public role: UserRoles = UserRoles.GUEST;

  constructor(user?: IUser) {
    if (user) {
      this.ID = user.ID ? user.ID : null;
      this.firstName = user.firstName ? user.firstName : '';
      this.lastName = user.lastName ? user.lastName : '';
      this.role = user.role ? user.role : UserRoles.GUEST;
    }
  }

  public get getRole(): string {
      return UserRoles[this.role];
  }
  public get getFullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
}

const user: User = new User({ ID: 1, firstName: 'Bruce', lastName: 'Wayne' });

@RyanCavanaugh
Copy link
Member

@andre-dw you declared getRole and getFullName as required properties and then didn't provide them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

6 participants