最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Why doesn't Typescript class "know" about its own properties? - Stack Overflow

programmeradmin2浏览0评论

We want to create a generic method on a superclass that accepts an argument that is the name of any property on the subclass that is of a certain type. Consider this (very contrived) example:

class CanUpcase {
    upcase<PropertyName extends keyof this>(
        propertyName: this[PropertyName] extends string ? PropertyName : never
    ) {
        return this[propertyName].toUpperCase(); // Property 'toUpperCase' does not exist on type 'this[this[PropertyName] extends string ? PropertyName : never]'.
    }
}

class User extends CanUpcase {
    age = NaN;

    name = ``;

    constructor() {
        super();

        this.upcase('name'); // Argument of type '"name"' is not assignable to parameter of type 'this["name"] extends string ? "name" : never'.ts(2345)
    }
}

const user = new User();
user.upcase('name'); // No error

We expected that upcase would accept 'name', since the 'name' property is a string.

However, while user.upcase('name') works as expected, an error is thrown by this.upcase('name') as shown.

Plus, within upcase, this[propertyName] is not recognized as a string.

  1. Why does this.upcase throw an error and not user.upcase?

  2. Why isn't this[propertyName] recognized as a string?

Thanks!

We want to create a generic method on a superclass that accepts an argument that is the name of any property on the subclass that is of a certain type. Consider this (very contrived) example:

class CanUpcase {
    upcase<PropertyName extends keyof this>(
        propertyName: this[PropertyName] extends string ? PropertyName : never
    ) {
        return this[propertyName].toUpperCase(); // Property 'toUpperCase' does not exist on type 'this[this[PropertyName] extends string ? PropertyName : never]'.
    }
}

class User extends CanUpcase {
    age = NaN;

    name = ``;

    constructor() {
        super();

        this.upcase('name'); // Argument of type '"name"' is not assignable to parameter of type 'this["name"] extends string ? "name" : never'.ts(2345)
    }
}

const user = new User();
user.upcase('name'); // No error

We expected that upcase would accept 'name', since the 'name' property is a string.

However, while user.upcase('name') works as expected, an error is thrown by this.upcase('name') as shown.

Plus, within upcase, this[propertyName] is not recognized as a string.

  1. Why does this.upcase throw an error and not user.upcase?

  2. Why isn't this[propertyName] recognized as a string?

Thanks!

Share Improve this question asked Mar 2 at 6:31 RobertAKARobinRobertAKARobin 4,2844 gold badges29 silver badges47 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

You make the child property available in a superclass with a generic parameter:

Playground

type KeysOfType<T extends object, V> = keyof {[K in keyof T as T[K] extends V ? K : never]: unknown};

class CanUpcase<T extends object> {
    upcase(propertyName: KeysOfType<T, string>) {
        return (this[propertyName] as string).toUpperCase();
    }
}


class User extends CanUpcase<User> {
    age = NaN;

    name = ``;

    constructor() {
        super();

        this.upcase('name'); // ok
    }
}

const user = new User();
user.upcase('name'); // No error

Autocompletion works also:

发布评论

评论列表(0)

  1. 暂无评论