title: How can I remove a wider type from a union type without removing its subtypes in TypeScript?
body: <p>Using the Exclude operator doesn't work.</p>
  
  <pre><code>type test = Exclude&lt;'a'|'b'|string, string&gt;
  // produces type test = never
  </code></pre>
  
  <p>I can understand why "except strings" also means excluding all the string literals, but how can I obtain <code>'a'|'b'</code> out of <code>'a'|'b'|string</code>?</p>
  
  <p>If needed, assume latest TypeScript.</p>
  
  <p>The usecase is as follows:</p>
  
  <p>Say a third party library defines this type:</p>
  
  <pre><code>export interface JSONSchema4 {
    id?: string
    $ref?: string
    $schema?: string
    title?: string
    description?: string
    default?: JSONSchema4Type
    multipleOf?: number
    maximum?: number
    exclusiveMaximum?: boolean
    minimum?: number
    exclusiveMinimum?: boolean
    maxLength?: number
    minLength?: number
    pattern?: string
    // to allow third party extensions
    [k: string]: any
  }
  </code></pre>
  
  <p>Now, what I want to do, is get a union of the KNOWN properties:</p>
  
  <pre><code>type KnownProperties = Exclude&lt;keyof JSONSchema4, string|number&gt;
  </code></pre>
  
  <p>Somewhat understandably, this fails and gives an empty type.</p>
  
  <p>If you are reading this but I was hit by a bus, the answer to this might be found in <a href="https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-414777939" rel="noreferrer">this GitHub thread</a>.</p>