How to get typescript to infer the literal string value for a type, rather than the generic `string` - Stack Overflow

I am writing a library to define schemas.Consider the following example:type Cardinality = 'many

I am writing a library to define schemas.

Consider the following example:

type Cardinality = 'many' | 'one';

type ValueType = 'string' | 'number';

interface ILinkDef<Source> {
  fwdCardinality: Cardinality;
  revNamespace: keyof Source;
  revCardinality: Cardinality;
  revLabel: string;
}

interface IAttrsDef {
  [label: string]: ValueType
}

interface ILinksDef<Source> {
  [label: string]: ILinkDef<Source>
}

interface ISchemaDef<Source> {
  [table: string]: {
    attrs: IAttrsDef;
    links: ILinksDef<Source>;
  };
}

class Schema<D extends ISchemaDef<any>> {
  defs: D
  constructor(
    defs: D,
  ) {
    this.defs = defs
  }
}

function schema<D extends ISchemaDef<D>>(defs: D) {
  return new Schema<D>(defs);
}

const s = schema({
  posts: {
    attrs: {
      title: 'string'
    },
    links: {
      owner: {
        fwdCardinality: 'one',
        revNamespace: 'users',
        revLabel: 'ownedPosts', 
        revCardinality: 'many'
      }      
    }
  },
  users: {
    attrs: {
      email: 'string'
    },
    links: {}
  }
})

type OwnerLink = typeof s.defs.posts.links.owner

Problem

OwnerLink returns the following inference:

type OwnerLink = {
  fwdCardinality: "one";
  revNamespace: "users";
  revLabel: string;
  revCardinality: "many";
}

I am really happy to have the literal values for fwdCardinality, revCardinality, etc.

However, I can't get revLabel to refine itself into it's literal value. I would love for revLabel to be 'ownedPosts'

Question

How could I get revLabel to keep the inference to it's literal argument, when possible?

Playground Link

I am writing a library to define schemas.

Consider the following example:

type Cardinality = 'many' | 'one';

type ValueType = 'string' | 'number';

interface ILinkDef<Source> {
  fwdCardinality: Cardinality;
  revNamespace: keyof Source;
  revCardinality: Cardinality;
  revLabel: string;
}

interface IAttrsDef {
  [label: string]: ValueType
}

interface ILinksDef<Source> {
  [label: string]: ILinkDef<Source>
}

interface ISchemaDef<Source> {
  [table: string]: {
    attrs: IAttrsDef;
    links: ILinksDef<Source>;
  };
}

class Schema<D extends ISchemaDef<any>> {
  defs: D
  constructor(
    defs: D,
  ) {
    this.defs = defs
  }
}

function schema<D extends ISchemaDef<D>>(defs: D) {
  return new Schema<D>(defs);
}

const s = schema({
  posts: {
    attrs: {
      title: 'string'
    },
    links: {
      owner: {
        fwdCardinality: 'one',
        revNamespace: 'users',
        revLabel: 'ownedPosts', 
        revCardinality: 'many'
      }      
    }
  },
  users: {
    attrs: {
      email: 'string'
    },
    links: {}
  }
})

type OwnerLink = typeof s.defs.posts.links.owner

Problem

OwnerLink returns the following inference:

type OwnerLink = {
  fwdCardinality: "one";
  revNamespace: "users";
  revLabel: string;
  revCardinality: "many";
}

I am really happy to have the literal values for fwdCardinality, revCardinality, etc.

However, I can't get revLabel to refine itself into it's literal value. I would love for revLabel to be 'ownedPosts'

Question

How could I get revLabel to keep the inference to it's literal argument, when possible?

Playground Link

Share Improve this question asked Nov 19, 2024 at 1:52 Stepan ParunashviliStepan Parunashvili 2,8456 gold badges35 silver badges57 bronze badges 2
  • the definition of ILinkDef specifies revLabel to be just string, though. Do you want to change it to a generic? – qrsngky Commented Nov 19, 2024 at 1:55
  • I would love to change it to be generic, but I am not sure how I would then 'fill' in that generic value with what is provided in the schema – Stepan Parunashvili Commented Nov 19, 2024 at 2:01
Add a comment  | 

1 Answer 1

Reset to default 1

Your original definition of ILinkDef specifies revLabel to be just string. It can be changed to a generic, though. For example:

type Cardinality = 'many' | 'one';

type ValueType = 'string' | 'number';

interface ILinkDef<Source, T extends string = string> {
  fwdCardinality: Cardinality;
  revNamespace: keyof Source;
  revCardinality: Cardinality;
  revLabel: T;
}

interface IAttrsDef {
  [label: string]: ValueType
}

interface ILinksDef<Source, T extends string = string> {
  [label: string]: ILinkDef<Source, T>
}

interface ISchemaDef<Source, T extends string = string> {
  [table: string]: {
    attrs: IAttrsDef;
    links: ILinksDef<Source, T>;
  };
}

class Schema<D extends ISchemaDef<any, any>> {
  defs: D
  constructor(
    defs: D,
  ) {
    this.defs = defs
  }
}

function schema<D extends ISchemaDef<D, T>, T extends string = string>(defs: D) {
  return new Schema<D>(defs);
}

const s = schema({
  posts: {
    attrs: {
      title: 'string'
    },
    links: {
      owner: {
        fwdCardinality: 'one',
        revNamespace: 'users',
        revLabel: 'ownedPosts', 
        revCardinality: 'many'
      }      
    }
  },
  users: {
    attrs: {
      email: 'string'
    },
    links: {}
  }
})

type OwnerLink = typeof s.defs.posts.links.owner

Playground Link

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745586365a4634565.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信