Keyboard layouts challenge
JavaScript (ES7), 282 273 251 250 bytes
Takes a keyboard layout ID k and an array of characters a in currying syntax (k)(a). Returns an array of translated characters.
The layout IDs are:

DVORAK: \$-32\$
COLEMAK: \$64\$
WORKMAN: \$160\$

k=&gt;a=&gt;a.map(c=&gt;1/(t=`1_3-2}w[vz8SsW]VZ1XJE&gt;UIDCHTN0BRL&quot;POYGK&lt;QF:/0=0{1xje.uidchtn0brl'poygk,qf;?0+995Oo6SFTD0UNEI0KY:0PRGL2J8sftd0unei0ky;0prgl2j998Ii5VMHRT0YUNEOLKP:0W0BFCD0J6vmhrt0yuneolkp;0w0bfcd0j5`.replace(/\d/g,n=&gt;15**n)[c.charCodeAt()+k])?c:t)

Try it online!
How it works
Compression
All three target layouts are stored in a single compressed string, where each character is either:

a translation character from QWERTY
a digit representing the number of consecutive characters that do not need to be translated

More specifically, a digit \$n\$ is interpreted as the length of the number \$15^n\$ in base \$10\$:
n | 15**n       | length
--+-------------+-------------
0 | 1           | 1
1 | 15          | 2
2 | 225         | 3
3 | 3375        | 4
4 | 50625       | 5 (not used)
5 | 759375      | 6
6 | 11390625    | 8
7 | 170859375   | 9 (not used)
8 | 2562890625  | 10
9 | 38443359375 | 11

For instance, #$%&amp;-()* in DVORAK is stored as 3-2 because #$%&amp; and ()* have identical mappings in QWERTY and only - is an actual translation.
In particular, 0123456789 is mapped the same way on all layouts and never has to be translated. Therefore, there's no possible ambiguity between a digit used for compression and a digit used for translation.
Decompression
To decompress the layout string, we replace each digit \$n\$ with \$15^n\$. For instance, 3-2 is decompressed as 3375-225.
Translation
For each character c in a, we extract the translation character t, using k as an offset in the uncompressed layout string, and test whether it's a digit with 1/t. If so, we output the original character c instead.