Skip to content

Why can I not specify _any_ type alias as an index signature parameter? #38112

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

Closed
5 tasks
robbiemu opened this issue Apr 22, 2020 · 2 comments
Closed
5 tasks
Labels
Duplicate An existing issue was already created

Comments

@robbiemu
Copy link

robbiemu commented Apr 22, 2020

Search Terms

type alias, alias, index signature parameter

Suggestion

Why can I not specify any type alias as an index signature parameter? Specifically, if each type in an alias is an instance of an accepted signature parameter.

This specifically supports goal #5, and obliquely supports goal #1 as well.

Use Cases

I notice that use cases where we want hinting to be exact, the hinting cannot alwys be fully expressive. for example, starting from:

export interface AttributesDictionary {
  [selector: string]: ElementAttribute[]
}

Here we provide an attributes dictionary that maps selectors to arrays of attributes. Such that we could iterate through the keys, querySelect on each key, then apply the attributes to each matching element.

The default use would probably be from document.querySelectorAll. A non-global use of this interface would instead be from el.querySelectorAll. If we want the use case to support applying attributes to el itself, we need a special case, ':root'. Now, the interface suffices but users of the interface won't know the special case from hinting alone. Better would be:

export interface AttributesDictionary {
  [selector: ':root' | string]: ElementAttribute[]
}

Examples

angular 9 example:

import { Directive, ElementRef, Input, Renderer2 } from '@angular/core'

export interface StyleSetting {
  styleName: string
  value: string | number
}
export interface DataAttribute {
  dataName: string
  value: string
}
export interface AttributeSetting {
  attributeName: string
  value: string
}
export type ElementAttribute = StyleSetting | DataAttribute | AttributeSetting

export interface AttributesDictionary {
  [selector: ':root' | string]: ElementAttribute[]
}

@Directive({
  selector: '[common-dynamic-attributes]'
})
export class DynamicAttributesDirective {
  private _dynamicAttributes: AttributesDictionary
  @Input('common-dynamic-attributes') set dynamicAttributes (
    attributes: AttributesDictionary
  ) {
    this._dynamicAttributes = attributes
    this.applyDynamicAttributes()
  }

  constructor (private elRef: ElementRef, private renderer: Renderer2) {}

  applyDynamicAttributes (
    attributes: AttributesDictionary = this._dynamicAttributes
  ) {
    Object.entries(attributes).forEach(([selector, rule]) => {
      if (selector == ':root') {
        this.applyRuleToElement(rule, this.elRef.nativeElement)
      } else {
        // some browsers may not support forEach on NodeList, so we wrap with Array.from
        Array.from(this.elRef.nativeElement.querySelectorAll(selector)).forEach(
          el => this.applyRuleToElement(rule, this.elRef.nativeElement)
        )
      }
    })
  }

  applyRuleToElement (rule: Array<ElementAttribute>, el: HTMLElement) {
    rule.forEach(setting => {
      if (setting.hasOwnProperty('attributeName')) {
        const attribute = setting as AttributeSetting
        el.setAttribute(attribute.attributeName, attribute.value)
      } else if (setting.hasOwnProperty('styleName')) {
        const style = setting as StyleSetting
        el.style[style.styleName] = style.value
      } else {
        const data = setting as DataAttribute
        el.dataset[data.dataName] = data.value
      }
    })
  }
}

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.
@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Apr 22, 2020
@RyanCavanaugh
Copy link
Member

See #1778

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants